有没有一种方法可以在嵌套函数中声明局部变量?

时间:2020-02-03 08:53:53

标签: matlab scope

有没有一种方法可以在嵌套函数中声明局部变量?

通过声明,我的意思是像往常一样命名一个变量,但是强制其作用域就地启动。想象一下在大型程序中间创建一个新的嵌套函数。您希望使用一些自然的变量名,并且您不必担心是否每次创建新变量时都必须检查现有的变量名。

为了描述所需的效果,我将使用两个示例。一小。一个人从视觉上更好地显示了这个问题。

简短示例

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

fn2fn3中,var指的是起始值为'a'的新变量,而在fn2var之外的起始变量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

有没有办法实现上述目标?

当前,我将尽最大努力确保使用特殊的非通用名称在本质上不是局部的名称变量和在本质上是局部的temp#,其中#是整数。 (我想在已知的上次使用之后clear变量有时会有所帮助。但是我宁愿不必这样做。局部变量太多了。)适用于小型程序。但是对于较大的程序,我发现很难避免无意中重写了已经在较高作用域级别命名的变量。这也增加了思考过程中的复杂程度,这对提高效率并不完全有效,因为在创建程序时,并非所有变量都显然不是局部变量,也不是局部变量。灵活的范围界定机制将非常有帮助。

我用Sublime Text编写程序,所以我对Matlab编辑器不熟悉。编辑器是否具有视觉防护/警告提示,以防止因不灵活的作用域而引起的错误?需要以视觉方式扫描整个程序的警告几乎没有用,但至少可以做到这一点。

3 个答案:

答案 0 :(得分:2)

否,如果变量也存在于外部作用域(即包含嵌套函数的函数)中,则在MATLAB中无法将嵌套函数变量声明为该函数的局部变量。

Nested Functions的行为已在MATLAB文档中进行了全面描述,您要问的内容是不可能的,或者至少没有记录在案。

具体说明支持的行为是

这意味着嵌套函数和包含它的函数都可以修改同一变量,而无需将该变量作为参数传递。

文档中没有提及防止此行为的补救措施。

答案 1 :(得分:2)

嵌套函数有一个非常特定的用例。它们并非旨在避免必须将数据作为输入和输出参数传递给函数,这对我来说就是您要尝试的。您的示例可以使用local functions编写:


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的大小已大大减小,可以放在一个屏幕中,并且更容易读取和调试。很明显,哪些函数会修改哪些变量。而且,您可以随意命名变量,因为没有变量作用域扩展到任何函数之外。

据我所知,嵌套函数只能用于捕获lambda(MATLAB中的函数句柄)的作用域,您可以编写一个函数来创建捕获lambda(嵌套函数的句柄)的函数。局部变量,然后将该lambda返回给调用方以供使用。这是一个强大的功能,尽管仅在特定情况下有用。除此之外,我还没有很好地使用嵌套函数。这只是您应避免使用IMO的方法。


这是带有捕获数据的lambda的示例(未经实际测试,只是为了给出一个想法;这也是一个相当愚蠢的应用程序,因为MATLAB具有更好的插值方式,请耐心等待)。 Create2DInterpolator采用分散的x,y和z样本值。它使用meshgridgriddata生成代表这些样本的规则2D网格。然后,它返回一个函数的句柄,该函数在该2D网格中进行内插以找到给定x和y的z值。此句柄可以在Create2DInterpolator函数外部使用,并包含我们创建的2D网格表示。基本上,interpolator是包含数据的函子类的实例。您可以通过编写自定义类来实现相同的操作,但是这将需要更多的代码,更多的工作以及附加的M文件。 in the documentation可以提供更多信息。

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 :(得分:2)

被定义为输入参数的变量是该函数的局部变量。因此,您可以将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_implfn2的实际实现,它继承了fn2继承的所有变量。 var是fn2_impl的本地变量,因为它是输入参数。

但是,我建议使用@CrisLuengo建议的局部函数。如果需要共享变量,则使用OO风格的编程比嵌套函数隐式共享更具可读性和可维护性。

  • 感谢@CrisLuengo,它使我注意到调用MATLAB函数时可以跳过输入参数。