控制Matlab中eval函数内的流程

时间:2014-08-10 18:20:54

标签: matlab eval continue

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

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

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

它会提示错误:

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

有谁知道为什么?

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

2 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

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

continue只能直接显示在forwhile循环中。但是,你可以破解这样的代码:

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

奇怪的是,x恰好出现在脚本的堆栈中。但是,这远远不是一段好的代码。切勿使用此方法。


编辑:关于"控制"范围eval

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

然而,我发现以下有趣的事情:

  1. 直接在continue

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

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

  2. 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循环?

  3. eval('foo') - 我真的不了解Matlab

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

    结果让我感到有些惊讶。

    ii =
         1
    ans =
        11
    ii =
         2
    ans =
        12
    >> 
    
  4. 思想:eval在独立的控制流中运行代码,但与当前的工作区共享其工作区。它是(某些但不完全)像isolated world模型,其中(在Matlab中)不同的代码片段可以与同一组变量交互,但在控制流的意义上不能相互交互。

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

    这不会改变我的解决方案:在任何情况下,尽量避免使用eval