我刚刚发现(令我惊讶的是)调用以下函数
function foo()
if false
fprintf = 1;
else
% do nothing
end
fprintf('test')
给出错误Undefined function or variable "fprintf"
。我的结论是变量的范围是在运行之前确定的(在我有限的理解中如何解释计算机语言,特别是Matlab的工作原理)。任何人都可以给我一些背景信息吗?
修改
我上面忘记提到的另一个有趣的事情是
function foo()
if false
fprintf = 1;
else
% do nothing
end
clear('fprintf')
fprintf('test')
生成Reference to a cleared variable fprintf
。
答案 0 :(得分:8)
似乎MATLAB JIT编译器第一次解析m文件时,它标识了函数中声明的所有变量。它似乎并不关心是否在无法访问的代码中声明了所述变量。因此,您的本地fprintf
变量会立即隐藏内置函数fprintf
。这意味着,就此函数而言,没有名为fprintf
的内置函数。
当然,一旦发生这种情况,函数中的每个引用fprintf
都会引用局部变量,并且由于变量从未实际创建过,因此尝试访问它会导致错误。
清除变量只是清除局部变量,如果它存在,不会将内置函数带回范围。
要显式调用内置函数,可以使用builtin
函数。
builtin( 'fprintf', 'test' );
上面的行总是在MATLAB命令行中打印文本,而不管可能影响fprintf
函数的局部变量。
答案 1 :(得分:8)
MATLAB在运行之前解析该函数。例如,它会查找变量名称,而不管激活(或不激活)这些变量的分支。也就是说,范围不是在运行时确定的。
ADDENDUM:我不建议这样做,但我看到很多人用MATLAB做事我不推荐。但是......考虑如果有人要定义他们自己的称为“假”的函数会发生什么。运行前解析器无法知道调用该函数会发生什么。
答案 2 :(得分:4)
有趣的情况。我怀疑是否有关于MATLAB解释器如何处理这个奇怪案例的详细信息,但文档中有几点需要注意......
MATLAB使用的function precedence order首先放置变量:
在假设名称与函数匹配之前,MATLAB会在当前工作空间中检查具有该名称的变量。
当然,在您的示例中,变量fprintf
实际上并不存在于工作空间中,因为从不输入条件语句的该分支。但是,关于变量命名的文档说明了这一点:
避免创建与函数同名的变量(例如
i
,j
,mode
,char
,size
和{{1 }})。通常,变量名称优先于函数名称。如果创建使用函数名称的变量,有时会得到意外结果。
这必须是“意外结果”之一,尤其是在实际未创建变量时。结论是MATLAB中必须有一些机制在运行时解析文件以确定给定范围内可能存在哪些可能的变量,其最终结果是函数仍然可以被变量隐藏出现在 m-file 中,即使它们最终未出现在工作区中。
编辑:更令人费解的是,exist
和which
等功能甚至都不知道该功能似乎被遮蔽了。在调用path
之前添加这些行:
fprintf
在错误发生之前给出此输出:
exist('fprintf')
which('fprintf')
表示他们仍然看到内置的ans =
5
built-in (C:\Program Files\MATLAB\R2012a\toolbox\matlab\iofun\fprintf)
。
答案 3 :(得分:2)
这些可能提供见解:
这可以为您提供有关阴影内容的一些信息:
which -all
(以下确认为错误) 其中一个问题是,Workspace结构和路径上的类具有特定的范围和类型优先级(如果您是我)可能会让您感觉不到。
E.g。在2017b:
% In C.m, saved in the current directory
classdef C
properties (Constant)
x = 100;
end
end
% In Command window
C.x = 1;
C.x % 100
C.x % 1 (Note the space)
C.x*C.x % 1
disp(C.x) % 1