【问题标题】:matlab - access variable in specific workspacematlab - 访问特定工作区中的变量
【发布时间】:2015-01-22 05:29:24
【问题描述】:

我需要类似于evalin的东西,但是不能递归使用Matlab的原始evalin。例如,我有函数 f0 调用 2 个其他函数 f11 和 f12:

function f0()
    [v1, v2] = deal(1, 1);

    f11();
    f12();

    disp(v1);
end

函数f11和f12使用变量v1,都调用函数f2:

function f11()
    v1 = evalin('caller', 'v1');

    f2();

    assignin('caller', 'v1', v1);
end

function f12()
    v1 = evalin('caller', 'v1');

    f2();

    assignin('caller', 'v1', v1);
end

并且函数 f2 应该使用 f0 工作区的变量 v1 和 v2:

function f2()
    v1 = evalin('caller', 'v1');    % get variable v1 from f11 or f12
                                    % since there is already a variable v1 
                                    % in f11 and f12's workspaces
    % TODO: get v2 from f0

    if v2 == 1
        v1 = v1 + 1;
    end

    assignin('caller', 'v1', v1);

end

有没有在 f11 和 f12 中不使用v2 = evalin('caller', 'v2') 的情况下使 TODO 成为可能?

【问题讨论】:

  • a) 为什么不使用函数参数? b) 或者你可以使用全局变量吗? c) 你为什么还要这样做?看起来不是个好主意!
  • 因为实际上我的 f0 有 ~ 100 个变量,就像一个 C 头文件,f11 和 f12 使用大约 10 个变量,f2 使用大约 10 个变量,并且有两个以上的函数 (f11, . ., f19) 调用 f2 :((
  • 如果从命令行调用f0(),即它是基本工作区,那么您可以在f2()中执行v2=evalin('base','v2')
  • @articuno:这是不正确的。然后变量仍在 f0 的工作区中,而不是在基础工作区中。
  • @scmg:是的,你是对的。我误解了。

标签: matlab recursion workspace


【解决方案1】:

这可能是组织函数之间数据传输的最糟糕的方式之一。功能的工作区被分开是有充分理由的,以保持事物的干净和有条理。

您正试图绕过设计该语言(以及许多其他共享这种工作区/范围分离的语言)的人设置的所有保护措施。 Matlab 中提供了这些“绕过”功能,以便在您进行原型设计时准时使用。它们不适合大量使用或最终解决方案(其中大多数实际上无法编译)。

  • 可能会造成极大的混乱(稍后对您而言,但如果其他人必须使用您的代码则更糟)。
  • 很难调试(您几乎提前知道变量的值,以了解从另一个工作区导入是否正确)。

您在评论中说将变量作为参数传递是复杂的,因为它们的数量,但是每次您调用像x = evalin('caller', 'x'); 这样的东西时,您都必须编写一整行代码来检索您的值。然后assignin('caller', 'x', x); 是另一行代码将其发回......这太疯狂了。

在你的函数输入参数中只包含x 不是更简单(更短)吗? (在输入中有 100 个变量仍然比有 200 行完整的代码来检索然后从不确定的位置重新发送这些值要快)。


推荐(如果可行):在参数中传递变量

为了使变量传递更容易,例如,您可以将它们全部收集到 structure(或 cell array)中:

[v1, v2] = deal(1, 1);
myVars.v1 = v1 ;
myVars.v2 = v2 ;

myVars = f11(myVars); %// you only have one variable to pass into your functions
myVars = f12(myVars); %// just make sure you retrieve it in output too

disp(myVars.v1);

然后

function myVars = f11()
    myVars = f2(myVars);
end

以此类推,只要将变量传递给下一个函数,然后在输出中检索它,这将适用于任何级别的递归。


推荐(如果以上不可能):使用嵌套函数

如果你定义你的函数f11()inside你的f0(),两个函数中同名的变量将被共享(两者都可见水平)。阅读documentation 了解更多详情。这样您就不需要多次致电evalin/assignin,因为该变量无处不在。您的函数必须以这种形式编写:

function f0()
[v1, v2] = deal(1, 1);

f11();
f12();

disp(v1);

    function f11()
        f2();
        function f2()
            if v2 == 1
                v1 = v1 + 1;
            end
        end
    end %// END function F11

    function f12()
        f2();
        function f2()
            if v2 == 1
                v1 = v1 + 1;
            end
        end
    end %// END function F12

end %// END function F0

Stack Exchange 不会呈现,但在 Matlab 编辑器中,您会注意到“共享”变量将以不同的颜色突出显示(提醒您它们的范围与标准变量不同)。

如果我运行f0(),我会得到:

>> f0
     3

这是预期的结果。如您所见,唯一的缺点是,如果您从f11()f12() 中调用f2(),则必须在每个函数中编写函数f2()(因此需要进行一些复制/粘贴) .除非在这个递归级别,你没有太多的变量要传递,所以你可以考虑在旁边写 f2() 并使用标准的变量传递方案。


可以工作,但不推荐

现在,如果您仍然热衷于编写多行代码来传递单个变量,那么仍然有两种选择:

我不喜欢使用global,所以我不会在这里详细说明。请记住,要使变量真正成为global,它必须在使用它的每个函数中声明为global

对于appdata 方法,您需要一个可供所有函数访问的“容器”。您可以为此使用“根”对象(标识符:0)。

例如,当你想存储一个变量时,你可以使用:

setappdata( 0 , 'v2' , v2 ) %// store the value of `v2` in a field named `'v2'` in the root object.

然后在您的任何函数中,获取值,对其进行处理,然后将其存储回来:

function f2()
    v1 = getappdata(0,'v1')     %// get the value of v1
    v2 = getappdata(0,'v2')     %// get the value of v2
    if v2 == 1
        v1 = v1 + 1;            %// modify the value of v1
    end
    v1 = setappdata(0,'v1',v1)  %// store the value of v1
end

在您的基本函数和f11()f12() 等中应用相同的原则......只要记住在修改后始终将任何值存储回来,以便它可用于下一个需要它的函数。

【讨论】:

  • 反馈:你的方法我都试过了。而将所有变量存储在结构中的方式对我来说是最方便的。也可以将struct声明为全局的,或者作为参数传递,远胜于setappdata和getappdata。
  • @scmg 嘿没问题,感谢您的反馈。寻找作为参数传递的struct 也是我的首选。这是最干净的选择。声明它global 也可以,但是使用全局变量时有一些潜在的风险,所以如果我能以不同的方式做事,我通常会避免它们。 setappdata/getappdata 在 GUI 应用程序中更有用,因为回调始终可以轻松访问重要变量,在您的情况下(仅限函数,相互调用)它会很笨重,而且确实不太实用。
【解决方案2】:

只是试图做到这一点:您的“变量”所持有的值应该与您希望对其执行的操作保持一致。只是在黑暗中开枪,但您是否尝试过面向对象来解决您的问题。

classdef myObj
properties
    v1;
    v2;
end
methods
    function f1(obj)
        ... do something here ....
        obj.v1 = ....;
    end
    function f2(obj)
        obj.f1();
    end
end

根据您的具体问题,这可能是获得正确递归的最简单方法。 OO in Matlab isnt that hard to learn

【讨论】:

  • 除了 Hoki 的回答之外,这对我来说也是一个很好的解决方案,谢谢 :-)
【解决方案3】:

您可以将f0() 的变量保存到文件中,然后在f2() 中调用load 方法将这些变量导入f2() 工作区。

【讨论】:

    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    相关资源
    最近更新 更多