11.10.4 Вложенные функции
Вложенные функции похожи на подфункции тем, что только главная функция видна снаружи файла. Однако они также позволяют дочерним функциям обращаться к локальным переменным в их родительской функции. Этот общий доступ имитирует использование глобальной переменной для обмена информацией — но глобальной переменной, которая не видна остальной части Octave. В качестве стратегии программирования такой обмен данными может создавать код, который трудно поддерживать. Рекомендуется использовать подфункции вместо вложенных функций, когда это возможно.
В качестве простого примера рассмотрим родительскую функцию foo, которая вызывает вложенную дочернюю функцию bar, с общей переменной x.
function y = foo ()
x = 10;
bar ();
y = x;
function bar ()
x = 20;
endfunction
endfunction
foo ()
⇒ 20 Обратите внимание, что для обмена x нет специальной синтаксической конструкции. Это может привести к проблемам с непреднамеренным обменом переменных между родительской функцией и ее дочерней функцией. В то время как обычно переменные наследуются, параметры и возвращаемые значения дочерней функции локальны для дочерней функции.
Теперь рассмотрим функцию foobar, которая использует переменные x и y. foobar вызывает вложенную функцию foo, которая принимает x в качестве параметра и возвращает y. foo затем вызывает bat, которая выполняет некоторые вычисления.
function z = foobar ()
x = 0;
y = 0;
z = foo (5);
z += x + y;
function y = foo (x)
y = x + bat ();
function z = bat ()
z = x;
endfunction
endfunction
endfunction
foobar ()
⇒ 10 Важно отметить, что x и y в foobar остаются нулевыми, так как в foo они являются соответственно возвращаемым значением и параметром. x в bat относится к x в foo.
Наследование переменных приводит к проблеме для eval и скриптов. Если новая переменная создается в родительской функции, не ясно, что должно произойти во вложенных дочерних функциях. Например, рассмотрим родительскую функцию foo с вложенной дочерней функцией bar:
function y = foo (to_eval)
bar ();
eval (to_eval);
function bar ()
eval ("x = 100;");
eval ("y = x;");
endfunction
endfunction
foo ("x = 5;")
⇒ error: can not add variable "x" to a static workspace
foo ("y = 10;")
⇒ 10
foo ("")
⇒ 100 Родительская функция foo не может создать новую переменную x, но дочерняя функция bar успешно это сделала. Более того, даже в операторе eval переменная y в bar является той же y, что и в родительской функции foo. Использование eval в сочетании с вложенными функциями лучше избегать.
Как и в случае с подфункциями, только первая вложенная функция в файле может быть вызвана извне. Внутри функции правила более сложные. В общем, вложенная функция может вызывать:
- Глобально видимые функции
- Любую функцию, которую может вызвать родитель вложенной функции
- Функции-сиблинги (функции, у которых одинаковые родители)
- Прямых дочерних функций
В качестве сложного примера рассмотрим родительскую функцию ex_top с двумя дочерними функциями, ex_a и ex_b. Кроме того, ex_a имеет еще две дочерние функции, ex_aa и ex_ab. Например:
function ex_top ()
## Can call: ex_top, ex_a, and ex_b
## Can NOT call: ex_aa and ex_ab
function ex_a ()
## Can call everything
function ex_aa ()
## Can call everything
endfunction
function ex_ab ()
## Can call everything
endfunction
endfunction
function ex_b ()
## Can call: ex_top, ex_a, and ex_b
## Can NOT call: ex_aa and ex_ab
endfunction
endfunction
© 1996–2022 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v7.2.0/Nested-Functions.html