目录
从 R2019b 开始,MATLAB 更改了名称解析规则,对变量、嵌套函数、局部函数和外部函数的优先顺序有所影响。新规则对名称解析进行了简化和标准化。可以参考函数优先顺序。
这些更改会影响 import 函数的行为。应分析并根据需要相应地更新代码。首先,请在代码中搜索 import 语句。例如,使用查找文件和文件夹搜索包含文本 import 的 .m 和 .mlx 文件。在评估以下更改的影响时,请参考这些搜索结果。
标识符在一个函数内只能用于一个目的。
从 R2019b 开始,如果将一个标识符先用作局部或导入函数,再用作变量,会导致错误。在以前的版本中,同一标识符可以在某个函数的作用域内用于多个不同目的,这会导致代码具有多义性。
如果此行为更改影响了您的代码,请重命名变量或函数,使它们具有不同名称。
从 R2019b 开始 | 更新后的代码 | R2019a 和更早版本 |
---|---|---|
名称 local 先用作 local 函数,再用作变量。这段代码出错。 function myfunc % local is an undefined variable local(1); % Errors local = 2; disp(local); end function local(x) disp(x) end | 将函数 local 重命名为 localFcn。 function myfunc localFcn(1); local = 2; disp(local); end function localFcn(x) disp(x) end | 以下代码先显示 1,然后显示 2。 function myfunc local(1); % local is a function local = 2; disp(local); end function local(x) disp(x) end |
没有显式声明的标识符可能不被视为变量
从 R2019b 开始,MATLAB® 不使用索引运算符来标识程序中的变量。以前,没有显式声明的标识符在使用冒号、end 或花括号进行索引时被视为变量。例如,在 x(a,b,:)、x(end)、x{a} 中,x 被视为变量。
以如下代码为例。此前,由于使用了冒号索引,MATLAB 会将 x 视为变量。从 R2019b 开始,如果路径上存在同名函数,MATLAB 会将 x 视为函数。
function myfunc
load data.mat; % data.mat contains variable x
disp(x(:))
end
如果打算使用 x 作为 data.mat 的变量而不是函数,请显式声明它。同样,要使用标识符 x 作为从脚本中获取的变量,请在调用脚本之前声明该变量。如果变量由以下函数隐式引入,则此新行为也适用:sim、eval、evalc 和 assignin。
下表给出了一些更新代码的示例。
更新前 | 更新后 |
---|---|
function myfunc load data.mat; disp(x(:)) end | function myfunc load data.mat x; disp(x(:)) end |
function myfunc2 myscript; % Contains variable x disp(x(:)) end | function myfunc2 x = []; myscript; disp(x(:)) end |
变量无法在父函数和嵌套函数之间隐式共享
从 R2019b 开始,仅当标识符在嵌套函数的父函数中显式声明为变量时,才能在该嵌套函数及其父函数之间共享该标识符作为变量。
例如,在以下代码中,myfunc 中的标识符 x 不同于嵌套函数中的变量 x。如果 x 是路径上的函数,MATLAB 会将 myfunc 中的 x 视为函数,并继续运行代码。否则,MATLAB 将引发错误。
function myfunc
nested;
x(3) % x is not a shared variable
function nested
x = [1 2 3];
end
end
在以前的版本中,如果 x 是路径上的函数,MATLAB 在 myfunc 中将其视为函数,在 nested 中将其视为变量。
如果 x 不是路径上的函数,MATLAB 会将其视为在 myfunc 和 nested 之间共享的变量。这导致了代码的输出取决于路径的状态。
要将标识符用作父函数和嵌套函数之间共享的变量,可能需要更新代码。例如,可以将标识符初始化为父函数中的空数组。
更新前 | 更新后 |
---|---|
function myfunc nested; x(3) function nested x = [1 2 3]; end end | function myfunc x = []; nested; x(3) function nested x = [1 2 3]; end end |
基于通配符导入的优先级发生更改
从 R2019b 开始,基于通配符导入的导入函数的优先级低于变量、嵌套函数和局部函数。在 R2019a 及更早版本中,函数中的导入会遮蔽局部函数和嵌套函数。
例如,在以下代码中,语句 local() 在基于通配符的导入中调用 myfunc/local 而不是 pkg1.local。语句 nest() 调用 myfunc/nest 而不是 pkg1.nest。
从 R2019b 开始 | R2019a 和更早版本 |
---|---|
function myfunc % Import includes functions local and nest import pkg1.* local() % Calls myfunc/local function nest end nest(); % Calls myfunc/nest end function local end | function myfunc % Import includes functions local and nest import pkg1.* local() % Calls pkg1.local and % displays warning since R2018a function nest end nest(); % Calls pkg1.nest end function local end |
在 import 的搜索结果中,查找包含通配符 (*) 的语句。
完全限定的导入函数不能与嵌套函数同名
从 R2019b 开始,如果完全限定的导入函数与同一作用域内的嵌套函数共享名称,则会引发错误。
从 R2019b 开始 | 更新后的代码 | R2019a 和更早版本 |
---|---|---|
此函数出错,因为它与同一作用域内的嵌套函数共享名称。 function myfunc import pkg.nest % Errors nest(); function nest end end | 要从 import 语句调用函数 nest,请重命名局部函数 myfunc/nest。 function myfunc import pkg.nest nest(); function newNest end end | 此函数从 import 语句中调用函数 nest。 function myfunc import pkg.nest nest(); % Calls pkg.nest function nest end end |
此函数出错,因为不支持声明与导入函数 function myvarfunc import pkg.nest % Errors nest = 1 end | 重命名变量 function myvarfunc import pkg.nest % Errors thisNest = 1 end | 此函数修改变量 function myvarfunc import pkg.nest nest = 1 % Modifies variable nest and % displays warning since R2018a end |
完全限定的导入函数会遮蔽同名的外层作用域定义
从 R2019b 开始,完全限定的导入函数会始终遮蔽同名的外层作用域定义。在 R2019a 及更早版本中,完全限定的导入函数如果遮蔽了外层作用域中的标识符,则它将被忽略。
从 R2019b 开始 | 更新后的代码 | R2019a 和更早版本 |
---|---|---|
局部函数 nest 从导入的包中调用函数 x。 function myfunc x = 1; function nest % Import function x import pkg1.x % Calls pkg1.x x() end end | 要在局部函数 nest 中使用变量 x,请将该变量作为参数传递。 function myfunc x = 1; nest(x) function nest(x1) % Import function x import pkg1.x % Calls pkg1.x with % variable x1 x(x1) end end | 在以下代码中,函数 nest 忽略导入的函数 x。 function myfunc x = 1; function nest % Import function x import pkg1.x % x is a variable x() end end |
未发现导入时的错误处理
从 R2019b 开始,无论是否有 Java®,无法解析的完全限定导入函数都会引发错误。在 R2019a 及更早版本中,MATLAB 的行为有所不同,具体取决于是否使用 -nojvm 选项启动 MATLAB。不要使用 javachk 和 usejava 等函数自定义错误消息。
从 R2019b 开始 | 更新后的代码 | R2019a 和更早版本 |
---|---|---|
使用 -nojvm 选项启动 MATLAB 时,以下代码会引发错误。 function myfunc import java.lang.String % Errors if ~usejava('jvm') % Statement never executes disp('This function requires Java'); else % Do something with Java String class end end | 取消对 usejava 的调用。 function myfunc import java.lang.String % Errors % Do something with java String class end | 使用 -nojvm 选项启动 MATLAB 时,以下代码会显示一条消息。 function myfunc import java.lang.String if ~usejava('jvm') % Display message disp('This function requires Java'); else % Do something with Java String class end end |
嵌套函数从父函数继承 import 语句
从 R2019b 开始,嵌套函数从父函数继承 import 语句。在 R2019a 及更早版本中,嵌套函数不从其父函数继承 import 语句。
从 R2019b 开始 | R2019a 和更早版本 |
---|---|
function myfunc % Package p1 has functions plot and bar import p1.plot import p1.* nest function nest plot % Calls p1.plot bar % Calls p1.bar end end | function myfunc % Package p1 has functions plot and bar import p1.plot import p1.* nest function nest plot % Calls plot function on path bar % Calls bar function on path end end |
复合名称解析优先级的更改
从 R2019b 开始,MATLAB 以另一种方式解析复合名称。复合名称包含以点相连的多个部分(例如,a.b.c),可用于引用包成员。在 R2019b 中,MATLAB 在解析复合名称时,将最长匹配前缀视为优先。在以前的版本中,优先顺序遵循一组更复杂的规则。
例如,假设包 pkg 包含具有静态方法 bar 的 foo 类,以及具有函数 bar 的 foo 子包。
+pkg/@foo/bar.m % bar is a static method of class foo
+pkg/+foo/bar.m % bar is a function in subpackage foo
在 R2019b 中,调用 which pkg.foo.bar 将返回包函数的路径。
which pkg.foo.bar
+pkg/+foo/bar.m
以前,在包和类同名的情况下,静态方法优先于包函数。
匿名函数可以同时包含已解析和未解析的标识符
从 R2019b 开始,匿名函数可以同时包含已解析和未解析的标识符。在以前的版本中,如果匿名函数中有任何标识符在创建时未解析,则该匿名函数中的所有标识符均为未解析。
从 R2019b 开始 | R2019a 和更早版本 |
---|---|
为了计算匿名函数,MATLAB 使用在 myscript 中定义的 x 调用局部函数 lf,因为匿名函数中的 lf 解析为局部函数。 function myfun myscript; % Includes x = 1 and lf = 10 f = @()lf(x); f() % Displays 'Inside lf' end % Local function to myfun function lf(y) disp('Inside lf'); end | MATLAB 将 lf 和 x 视为未解析的标识符,并使用 x 对来自 myscript 的变量 lf 进行索引。 function myfun myscript; % Includes x = 1 and lf = 10 f = @()lf(x); f() % Displays 10 end % Local function to myfun function lf(y) disp('Inside lf'); end |