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/v6.4.0/Nested-Functions.html