Есть ли способ объявить локальную переменную во вложенных функциях? - PullRequest
2 голосов
/ 03 февраля 2020

Есть ли способ объявить локальную переменную во вложенной функции?

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

Чтобы описать желаемый эффект, я ' Я буду использовать два примера. Один минимальный. Один показывает проблему немного лучше визуально.

Краткий пример

function fn1
    var = 1
    function fn2
        local var = 'a';
        function fn3
        end
    end
end

В пределах fn2 и fn3, var относится к новой переменной со начальным значением 'a', в то время как снаружи fn2, var с начальным значением 1 по-прежнему доступно как обычно.

Длинный пример

function fn1
    var = 1;
    var2 = 2;
    function fn2
        var2 = 'I can access var2 from fn1. Happy.'
        local var = 'a';  % remove local to run this snippet

        fn3;
        function fn3
            var2 = 'I can access var2 from fn1. Happy.'
            var = 'fn2 cannot safely use variable name var because it may have been used in fn1. But var is the natural name to use in fn2. Sad.';

            var = 1;
            var2 = 2;
        end
    end
    function fn4
        var2 = 'I can also access var2 from fn1. Also happy.'
        var = 'If only local scoping works, I would still be able to access var. Would be happy.';
    end

    fn4;
    fn2;
    var,
    var2,
end
%% desired output, but not real
>> fn1;
var =
    1
var2 =
    2

Есть ли способ выполнить sh выше?

В настоящее время я делаю все возможное, чтобы переменные имен, которые не являются локальными по природе, имели специальные не обобщенные c имена и переменные имен, которые явно являются локальными по природе temp#, где # - целое число. (Полагаю, clear переменные после известного последнего использования могут иногда помочь. Но я бы предпочел не делать этого. Локальных переменных слишком много.) Это работает для небольших программ. Но с большими программами мне трудно избежать непреднамеренной перезаписи переменной, которая уже была названа на более высоком уровне охвата. Это также добавляет уровень сложности в мыслительный процесс, что не совсем хорошо для эффективности, потому что при создании программы не все переменные либо явно локальные, либо явно не локальные. Очень полезен гибкий механизм видимости.

Я пишу свои программы в Sublime Text, поэтому я не знаком с редактором Matlab. Есть ли у редактора визуальная защита / предупреждения от ошибок, возникающих из-за негибкой области видимости? Предупреждение, которое требует визуального сканирования всей программы, едва ли полезно, но, по крайней мере, это будет что-то.

Ответы [ 3 ]

2 голосов
/ 03 февраля 2020

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


function fn1
    var = 1;
    var2 = 2;
    [var,var2] = fn4(var,var2);
    var2 = fn2(var2);
    var,
    var2,
end

function var2 = fn2(var2)
    var2 = 'I can access var2 from fn1. Happy.'
    var = 'a';  % remove local to run this snippet

    [var,var3] = fn3(var,var2);
end

function [var,var2] = fn3(var,var2)
    var2 = 'I can access var2 from fn1. Happy.'
    var = 'fn2 cannot safely use variable name var because it may have been used in fn1. But var is the natural name to use in fn2. Sad.';

    var = 1;
    var2 = 2;
end

function [var,var2] = fn4(var,var2)
    var2 = 'I can also access var2 from fn1. Also happy.'
    var = 'If only local scoping works, I would still be able to access var. Would be happy.';
end

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

Насколько я знаю, вложенные функции могут быть использованы только для захвата области видимости в лямбда-выражении (дескриптор функции в MATLAB говорят), Вы можете написать функцию, которая создает лямбду (дескриптор вложенной функции), которая захватывает локальную переменную, а затем возвращает эту лямбду вашему вызывающему пользователю для использования. Это мощная функция, но полезная только ситуативно. Помимо этого, я не нашел хорошего использования вложенных функций. Это просто то, что вы должны стараться избегать IMO.


Вот пример лямбды с захваченными данными (на самом деле не проверено, это просто для того, чтобы дать представление; также это довольно глупое приложение, так как MATLAB имеет лучшие способы интерполяции, просто терпите меня). Create2DInterpolator принимает значения выборки x, y и z. Он использует meshgrid и griddata для генерации регулярной двумерной сетки, представляющей эти выборки. Затем он возвращает дескриптор функции, которая интерполирует в этой двумерной сетке, чтобы найти значение z для данных x и y. Этот дескриптор может использоваться вне функции Create2DInterpolator и содержит созданное нами 2D-представление сетки. По сути, interpolator является экземпляром класса функторов, который содержит данные. Вы можете реализовать то же самое, написав собственный класс, но для этого потребуется намного больше кода, гораздо больше усилий и дополнительный M-файл. Больше информации можно получить в документации .

interpolator = Create2DInterpolator(x,y,z);
newZ = interpolator(newX,newY);

function interpolator = Create2DInterpolator(x,y,z)
   [xData,yData] = meshgrid(min(x):max(x),min(y):max(y));
   zData = griddata(x,y,z,xData,yData);
   interpolator = @InterolatorFunc;

   function z = InterolatorFunc(x,y)
      z = interp2(xData,yData,zData,x,y);
   end
end
2 голосов
/ 03 февраля 2020

Переменные, которые определены как входные аргументы, являются локальными для функции. Таким образом, вы можете определить var в качестве входного аргумента fn2*:

function fn2 (var)
...
end

Однако, если вы хотите определить fn2 без изменения его сигнатуры, вам нужно определить дополнительный уровень вложенности:

function fn1
    var = 1;
    var2 = 2;
    function fn2

      fn2_impl([]);
      function fn2_impl (var)
        var2 = 'I can access var2 from fn1. Happy.'
        var = 'a';  % remove local to run this snippet

        fn3;
        function fn3
            var2 = 'I can access var2 from fn1. Happy.'
            var = 'fn2 cannot safely use variable name var because it may have been used in fn1. But var is the natural name to use in fn2. Sad.';

            var = 1;
            var2 = 2;
        end
      end
    end
    function fn4
        var2 = 'I can also access var2 from fn1. Also happy.'
        var = 'If only local scoping works, I would still be able to access var. Would be happy.';
    end

    fn4;
    fn2;
    var,
    var2,
end

Здесь fn2_impl - это фактическая реализация fn2, и она наследует все переменные, унаследованные fn2. var локально для fn2_impl, потому что это входной аргумент.

Однако я рекомендую локальные функции, как предложено @ CrisLuen go. Если переменные должны использоваться совместно, использование OO-стиля программирования более читабельно и легко поддерживается, чем неявное совместное использование вложенными функциями.

  • Благодаря @ CrisLuen go, который отметил, что можно пропустить ввод аргументы при вызове функций MATLAB.
2 голосов
/ 03 февраля 2020

Нет, в MATLAB нет способа объявить переменную вложенной функции локальной для этой функции, если переменная также существует во внешней области (т. Е. Функция, содержащая вложенную функцию).

поведение вложенных функций полностью описано в документации MATLAB, и то, что вы запрашиваете, невозможно или, по крайней мере, не задокументировано.

В частности, указано, что поддерживаемое поведение

Это означает, что как вложенная функция, так и содержащая ее функция могут изменять одну и ту же переменную, не передавая эту переменную в качестве аргумента.

, и никакое средство для предотвращения такого поведения не упоминается в документация.

...