Main Content

针对 R2019b 对函数优先顺序的更改更新代码

从 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 作为从脚本中获取的变量,请在调用脚本之前声明该变量。如果变量由以下函数隐式引入,则此新行为也适用:simevalevalcassignin

下表给出了一些更新代码的示例。

更新前更新后
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 会将其视为在 myfuncnested 之间共享的变量。这导致了代码的输出取决于路径的状态。

要将标识符用作父函数和嵌套函数之间共享的变量,您可能需要更新代码。例如,您可以将标识符初始化为父函数中的空数组。

更新前更新后
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

此函数出错,因为不支持声明与导入函数 nest 同名的变量。

function myvarfunc
import pkg.nest  % Errors 
nest = 1
end

重命名变量 nest

function myvarfunc
import pkg.nest  % Errors 
thisNest = 1
end

此函数修改变量 nest

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。不要使用 javachkusejava 等函数自定义错误消息。

从 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 包含具有静态方法 barfoo 类,以及具有函数 barfoo 子包。

+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 将 lfx 视为未解析的标识符,并使用 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 

另请参阅

相关主题