Matlab中评估函数内的控制流

Posted

技术标签:

【中文标题】Matlab中评估函数内的控制流【英文标题】:Control flow within an eval function in Matlab 【发布时间】:2014-08-10 18:20:53 【问题描述】:

如果我将 continue 作为 eval() 指令的参数包含在内,则它不会按预期工作。例如,执行以下代码时:

listParam = 'a','b','c';
a = 17;
b = NaN;
c = 4;

for ii=1:numel(listParam),
    eval(['if isnan(',listParamii,'), continue; end']);
    disp(['The parameter ', listParamii, ' is not a NaN.']);
end

会提示错误:

Error: A CONTINUE may only be used within a FOR or WHILE loop.

有人知道为什么吗?

注意:我知道我应该避免使用eval(),并且可以将前面的示例重构为更好的编码;但我发现了一个奇怪的行为,我很好奇发生了什么。

【问题讨论】:

【参考方案1】:

您传递给eval 的表达式本身必须是一个有效的matlab 表达式,不考虑任何周围的代码。这意味着每个continue 必须被一个循环包围。要么将周围的for 放在您的评估中,要么将continue 放在外面。

【讨论】:

+1 关于eval 的参数是独立于“正常”代码进行评估这一事实的任何参考? 我更新了我的答案以使其准确。 @LuisMendo:我没有任何参考,但据我了解,代码根本不是有效的表达方式。 @LuisMendo 关于eval的范围,我做了一些简单的实验;如果将continue 放在单独的foo.m 脚本中(单行表示continue),并且在主脚本中使用eval('foo'),则for 循环将得到控制。 @Yvon 这很有趣!【参考方案2】:

正如@Daniel 所指出的,eval 由脚本调用,而不是由for 循环直接控制。你可以这样想:eval 中的continue 会将程序计数器移动到eval 内代码的头部,但不会移动到for 循环的头部;这当然会失败,因为 Matlab 不允许在行之间跳转。

continue 只能直接出现在 forwhile 循环内。但是,您可以像这样破解代码:

for ii=1:numel(listParam),
    eval(['if isnan(',listParamii,'), x=1; else, x=0; end']);
    if x
        continue;
    end
    disp(['The parameter ', listParamii, ' is not a NaN.']);
end

奇怪的是,x 恰好出现在脚本的堆栈中。然而,这远非一段好的代码。永远不要使用这种方法。


编辑:关于eval 的“控制”范围。

我不是在谈论eval 的变量范围/工作区。提示可以在多个文档中找到,例如 this 和 this。简而言之,eval 使用“当前”工作区。

但是,我发现以下一些有趣的事情:

    直接在eval中运行continue

    for ii = 1:2
        eval('continue')
        ii+10
    end
    

    这根本失败,如问题所示。错误是Error: A CONTINUE may only be used within a FOR or WHILE loop.,这意味着eval 内的continue 找不到任何循环(for 循环)。

    for 循环中调用单独的脚本

    for ii = 1:2
        foo
        ii+10
    end
    

    而脚本foo.m

    ii
    continue
    

    首先,在foo.m Mlint 给出了一个红线警告,这通常表示一个可以阻止代码运行的错误,说CONTINUE is only valid in a FOR or WHILE loop。但是在 foo.m 上按 F5 没有任何问题 - 事实上,在任何地方运行单个 continue 不会导致代码崩溃。

    运行主脚本给出输出

    ii =
         1
    ii =
         2
    >> 
    

    ....所以foo.m 捕获for 循环?

    eval('foo') - 我真的不懂Matlab

    for ii = 1:2
        eval('foo')
        ii+10
    end
    

    结果让我有点吃惊。

    ii =
         1
    ans =
        11
    ii =
         2
    ans =
        12
    >> 
    

想法:eval 在独立的控制流中运行代码,但与当前的共享其工作区。它(但不完全是)类似于isolated world 模型,其中(在 Matlab 中)不同的代码段可以与同一组变量交互,但在控制流的意义上不能相互交互。

不幸的是,我无法找到任何现有资源作为参考来证明这个想法。

这不会改变我的解决方案:无论如何,尽量避免使用eval

【讨论】:

以上是关于Matlab中评估函数内的控制流的主要内容,如果未能解决你的问题,请参考以下文章

我怀疑 re.match 弄乱了控制流

新手必看攻略,MySQL中的控制流函数!!!

新手必看攻略,MySQL中的控制流函数!!!

控制流函数和字符串函数(不懂的建议收藏,满满的干货)

控制流函数和字符串函数(不懂的建议收藏,满满的干货)

mysql中常用的控制流函数