MATLAB错误?为函数和变量使用相同名称时出现"未定义的函数或变量"错误

tar*_*els 8 matlab scope function

在MATLAB中使用函数作为"常量"变量的偶尔会很方便.但是当我最近使用此功能时,我遇到了意外错误.当我在下面运行MWE时,Undefined function or variable 'a'.尽管功能在同一个文件中清晰可用,但我得到了错误.当我发表if声明时,错误消失了.这似乎暗示MATLAB预先解释a为变量,即使永远不会到达变量赋值行,忽略了存在同名函数的事实.这是一个MATLAB错误还是某种想要的行为?

这是MWE:

function matlabBugTest(  )
    if false
        a = 'foo';
    end
    a
end
function b = a()
    b = 'bar';
end
Run Code Online (Sandbox Code Playgroud)

跟进:

我知道有意为变量和函数使用相同的名称似乎很奇怪,所以我将举例说明这可能有用.例如,您可能希望使用函数来存储某些常量(如文件路径),但也希望能够在找不到该函数时使用不同的值.这种情况可能如下:

if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));
Run Code Online (Sandbox Code Playgroud)

我知道语言设计决策通常是困难和复杂的,但MATLAB选择忽略同名函数的一个更不幸的后果是它破坏了函数和脚本/命令行之间的兼容性.例如,以下在脚本中运行时没有问题:

if false
    a = 'foo';
end
a
Run Code Online (Sandbox Code Playgroud)

其中函数a(如上所示)保存在自己的文件中.

Tro*_*kin 10

它与Matlab如何在编译时执行名称绑定有关.因为matlabBugTest有一个分配值的行a,a被确定为一个变量,后一行a是对该变量的引用而不是对本地函数的调用.更现代的Matlab版本,比如我的R2015a安装,提供了更清晰的错误信息:

在编译时,"a"被确定为变量,并且该变量未初始化."a"也是一个函数名称,MATLAB的早期版本将调用该函数.但是,MATLAB 7禁止在与函数和变量相同的上下文中使用相同的名称.

这不是一个错误,因为它是由命名方案引入的歧义,给出了一个默认的解决方法,如果你之前从未遇到过问题并且m-lint没有标记它,这可能很烦人.当变量在没有事先初始化的情况下进入工作空间时,会发生类似的行为.

因此,解决方案是将函数或变量的名称更改为不同的东西,我认为这是好的做法.


在考虑你的后续例子时,我注意到在函数中移动事物时有一些有趣的行为.首先,如果函数是外部函数或嵌套函数,则可以通过Suever的答案得到很好讨论.但是,如果函数是本地函数,只要初始化函数或将其显式转换为变量,就可以通过在将函数转换为变量之前调用函数来绕过限制(至少可以在我的R2014b和R2015a安装中).在某一点.通过案例,以下机构的matlabBugTest表现如下:

我不完全确定为什么这种行为是这样的,但显然解析器根据函数的范围和符号出现的顺序以及在什么上下文中处理不同的事情.

所以假设这种行为没有也不会改变,你可以尝试这样的事情:

pathConstant = pathConstant;
if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));
Run Code Online (Sandbox Code Playgroud)

虽然,完全是个人意见,我会做类似的事情

pathConstant = getPathConstant();
if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));
Run Code Online (Sandbox Code Playgroud)

关于打破"函数和脚本/命令行之间的兼容性",我并不认为这是一个问题,因为当涉及到Matlab时,它们是两个完全不同的上下文.您不能在命令行或脚本文件中定义命名函数; 因此,Matlab JIT没有任何负担可以正确无误地确定符号是函数调用还是变量,因为每行都是按顺序执行而不是编译(除了某些代码块,JIT旨在识别和优化脚本中的循环).现在至于为什么上面的声明工作起作用,我不完全确定,因为它依赖于我一无所知的Matlab JIT(我也没有参加编译器课程,所以如果我不能形成学术上的理由通缉).

  • 有趣.我正在运行R2016a,奇怪的是没有给出这样一个有用的错误信息. (2认同)