Что такое вложенные функции?Для чего они нужны?

StackOverflow https://stackoverflow.com/questions/521103

Вопрос

Я никогда не использовал вложенные функции, но видел ссылки на них на нескольких языках (а также вложенные классы, которые, как я предполагаю, связаны).

  • Что такое вложенная функция?
  • Почему?!?
  • Что вы можете сделать с вложенной функцией такого, чего не можете сделать никаким другим способом?
  • Что вы можете сделать с вложенной функцией, которая сложна или неэлегантна без вложенных функций?

Я предполагаю, что вложенные функции - это просто артефакт обработки всего как объекта, и если объекты могут содержать другие объекты, то это следует.

Имеют ли вложенные функции область видимости (в общем, я полагаю, языки различаются в этом) точно так же, как переменные внутри функции имеют область видимости?

Пожалуйста, добавьте язык, на который вы ссылаетесь, если вы не уверены, что ваш ответ не зависит от языка.

-Адам

Это было полезно?

Решение

Одним из популярных способов использования вложенных функций является закрытиялексически ограниченный объем язык с первоклассными функциями можно использовать функции для хранения данных.Простым примером на схеме является счетчик:

(define (make-counter)
  (let ((count 0))                ; used to store the count
    (define (counter)             ; this is the counter we're creating
      (set! count (+ count 1))    ; increment the count
      count)                      ; return the new count
    counter))                     ; return the new counter function

(define mycounter (make-counter)) ; create a counter called mycounter

(mycounter)                       ; returns 1

(mycounter)                       ; returns 2

В этом примере мы помещаем функцию counter внутрь функции make-counter, и, возвращая эту внутреннюю функцию, мы можем получить доступ к данным, доступным для counter, когда он был определен.Эта информация является частной для данного экземпляра mycounter - если бы мы создали другой счетчик, он использовал бы другое место для хранения внутреннего счета.Продолжая предыдущий пример:

(define mycounter2 (make-counter))

(mycounter2)                      ; returns 1

(mycounter)                       ; returns 3

Другие советы

Это полезно для рекурсии, когда есть только 1 метод, который когда-либо его вызовет

string[] GetFiles(string path)
{
  void NestedGetFiles(string path, List<string> result)
  {
    result.AddRange( files in the current path);
    foreach(string subPath in FoldersInTheCurrentPath)
      NestedGetFiles(subPath, result);
  }

   List<string> result = new List<string>();
   NestedGetFiles(path, result);
   return result.ToArray();
}

Приведенный выше код полностью составлен, но основан на C #, чтобы дать представление о том, что я имею в виду.Единственный метод, который может вызывать NestedGetFiles, - это метод GetFiles .

Вложенная функция - это просто функция внутри другой функции.

Да, это результат того, что все является объектом.Поскольку у вас могут быть переменные, видимые только в области видимости функции, а переменные могут указывать на функции, у вас может быть функция, на которую ссылается локальная переменная.

Я не думаю, что есть что-то, что вы можете сделать с помощью вложенной функции, без чего вы абсолютно не могли бы обойтись.Хотя во многих случаях это имеет смысл.А именно, всякий раз, когда функция является "подфункцией" какой-либо другой функции.

Обычный вариант использования для меня - это когда функция выполняет много сложной логики, но то, что функция вычисляет / возвращает, легко абстрагировать для всех случаев, продиктованных логикой.

(C#) :Я использую это, чтобы упростить просмотр объектов в браузере и лучше структурировать свои классы.Как класс Wheel, вложенный в класс Truck.

Не забывайте об этой детали :"Вложенные типы могут получать доступ к закрытым и защищенным элементам содержащего типа, включая любые унаследованные закрытые или защищенные элементы".

Вложенные функции позволяют вам инкапсулировать код, который имеет отношение только к внутренней работе одной функции внутри этой функции, в то же время позволяя вам отделять этот код для удобства чтения или обобщения.В некоторых реализациях они также разрешают доступ к внешней области.В D:

int doStuff() {
    int result;
    void cleanUpReturn() {
        myResource1.release();
        myResource2.release();
        return result * 2 + 1;
    }

    auto myResource1 = getSomeResource();
    auto myResource2 = getSomeOtherResource();
    if(someCondition) {
        return cleanUpReturn();
    } else {
        doSomeOtherStuff();
        return cleanUpReturn();
    }
}

Конечно, в данном случае это также можно было бы обработать с помощью RAII, но это всего лишь простой пример.

Они также могут быть полезны, если вам нужно передать функцию другой функции в качестве аргумента.Они также могут быть полезны для создания заводских функций для заводских функций (в Python):

>>> def GetIntMaker(x):
...   def GetInt():
...     return x
...   return GetInt
... 
>>> GetInt = GetIntMaker(1)
>>> GetInt()
1

Вложенная функция - это просто функция, определенная в теле другой функции.Почему?Пожалуй, единственная причина, о которой я мог бы подумать навскидку, - это вспомогательная или служебная функция.

Это надуманный пример, но потерпите меня.Допустим, у вас была функция, которая должна была обработать результаты двух запросов и заполнить объект значениями из одного из запросов.Вы могли бы сделать что-то вроде следующего.

function process(qryResult q1, qryResult q2) {

   object o;
   if (q1.someprop == "useme") {
       o.prop1 = q1.prop1;
       o.prop2 = q1.prop2;
       o.prop3 = q1.prop3;
   } else if (q2.someprop == "useme") {
       o.prop1 = q2.prop1;
       o.prop2 = q2.prop2;
       o.prop3 = q2.prop3;
   }

   return o;

}

Если у вас было 20 свойств, вы дублируете код для настройки объекта снова и снова, что приводит к созданию огромной функции.Вы могли бы добавить простую вложенную функцию для копирования свойств из запроса в объект.Вот так:

function process(qryResult q1, qryResult q2) {

   object o;
   if (q1.someprop == "useme") {
       fillObject(o,q1);
   } else if (q2.someprop == "useme") {
       fillObject(o,q2);
   }

   return o;

   function fillObject(object o, qryResult q) {
       o.prop1 = q.prop1;
       o.prop2 = q.prop2;
       o.prop3 = q.prop3;
   }


}

Это делает вещи немного чище.Обязательно ли это должна быть вложенная функция?Нет, но вы можете захотеть сделать это таким образом, если функция process является единственной, которая должна была бы выполнить это копирование.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top