Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

函数参数验证

参数验证简介

函数参数验证是一种对函数输入参数声明特定限制的方法。使用参数验证,您可以约束函数输入值的类、大小和其他方面,而无需在函数体中编写代码来执行这些测试。

函数参数验证是声明性的,这使得 MATLAB® 桌面工具能够通过检查特定代码块来提取关于函数的信息。通过声明输入参数的要求,您可以消除繁琐的参数检查代码,并提高代码的可读性、稳健性和可维护性。

函数参数验证语法简化了定义可选参数、重复参数和名称-值参数的过程。该语法还使您能够以一致的方式定义默认值。

何时使用参数验证

在函数定义中,您可以选择是否使用函数参数验证。如果函数可由任何代码调用,并且在执行函数代码之前必须确定输入的有效性,则参数验证能起到很大帮助。对于那些为他人使用而设计的函数,如能对参数输入施加适当限制,并允许基于函数输入返回特定错误消息,也可使用户受益。

何时不需要验证

在局部和私有函数中,以及在私有或受保护方法中,调用方知道输入要求,因此可以使用有效参数调用这些类型的函数。

何时不允许验证

在嵌套函数、抽象方法或句柄类析构函数方法中,不能使用参数验证语法。有关方法中参数验证的详细信息,请参阅类方法中的参数验证

arguments 代码块语法

函数在以关键字 argumentsend 起止的代码块中定义参数验证。如果使用,arguments 代码块必须在函数的第一个可执行代码行之前开始。

您可以在一个函数中使用多个 arguments 代码块,但是,所有这些代码块必须出现在不属于 arguments 代码块的代码之前。

下面代码中突出显示的部分展示了参数验证的语法。

函数参数声明可以包括以下任何一种限制:

  • 大小 - 每个维度的长度,以圆括号括起

  • 类 - 单个 MATLAB 类的名称

  • 函数 - 以逗号分隔的验证函数列表,以花括号括起

您还可以在该参数的函数验证声明中为输入参数定义默认值。默认值必须满足对该参数声明的限制。

大小

验证大小是输入参数的维数,用非负整数或冒号 (:) 指定。冒号表示该维度中允许任何长度。您不能对维度使用表达式。在函数调用中分配给参数的值必须与指定的大小兼容,否则 MATLAB 会引发错误。

MATLAB 索引赋值规则适用于大小设定。例如,1×1 值与指定为 (5,3) 的大小兼容,因为 MATLAB 应用标量扩展。此外,MATLAB 行-列转换也适用,因此指定为 (1,:) 的大小可以接受 1×n 和 n×1 的大小。

下面给出了一些示例:

  • (1,1) - 输入必须精确为 1×1。

  • (3,:) - 第一个维度必须为 3,第二个维度可以是任何值。

如果不指定大小,则允许任何大小,除非受到验证函数的限制。

验证类是单个类的名称。赋给函数输入的值必须属于指定的类或可转换为指定的类。使用 MATLAB 支持的任何 MATLAB 类或外部定义的类,但不包括 Java 类、COM 类和不使用 classdef 关键字的 MATLAB 类定义(在 MATLAB 软件版本 7.6 之前定义的类)。

下面给出了一些示例:

  • char - 输入必须属于 char 类,或是 MATLAB 可以转换为 char 的值,例如 string

  • double - 输入可以是任意精度的数值。

  • cell - 输入必须为元胞数组。

  • 用户定义的类(如枚举类)可以将输入限制为更具体的值,并使您能够控制支持何种转换。

如果不指定类,则允许任何类,除非受到验证函数的限制。

验证函数

验证函数是一个 MATLAB 函数,如果参数值不满足某些要求,该函数会引发错误。验证函数不返回值,并且与类和大小不同,验证函数无法更改它们正在验证的参数的值。

在验证过程中,MATLAB 将参数值传递给为该参数列出的每个验证函数。传递给验证函数的值是在设定类和大小时进行任意转换之后的结果。MATLAB 从左到右调用每个函数,并引发遇到的第一个错误。

有关预定义的验证函数的表,请参阅参数验证函数

默认值

参数默认值可以是满足大小、类和验证函数要求的任何常量或表达式。在参数声明中指定默认值会使参数变为可选。当参数不包含在函数调用中时,MATLAB 将使用默认值。默认值表达式在每次使用默认值时进行计算。

注意

由于 MATLAB 仅在不带参数值调用函数时才验证默认值,因此无效的默认值仅在不带相应参数值调用函数时才会导致错误。

可选参数必须位于函数签名中和 arguments 代码块中的必需参数后。有关可选参数的详细信息,请参阅必需和可选位置参数

验证顺序

参数在 arguments 代码块中自上而下进行验证。MATLAB 按照特定顺序验证参数声明的每个部分。首先验证类,然后验证大小。类和大小验证的结果传递给验证函数。每个步骤均为可选的,具体取决于类、大小和验证函数是否在参数声明中。

有关详细信息,请参阅参数验证的顺序

转换为声明的类和大小

由于标准 MATLAB 转换规则,类验证和大小验证都可以更改输入参数的值。因此,函数体中经过验证的值可能不同于调用函数时传递的值。转换规则派生自 MATLAB 对索引赋值应用的规则,形式如下:

A(indices) = value

MATLAB 可以确定左侧值对类和大小有要求,并且在某些情况下,可以将右侧值转换为所需的类和大小。

要了解相关信息,请参阅避免类和大小转换

参数验证示例

arguments 代码块指定三个输入的大小和类。

function out = myFunction(A, B, C)   
    arguments
        A (1,1) string 
        B (1,:) double
        C (2,2) cell
    end

    % Function code
    ...
end

在此函数中,变量必须满足以下验证要求:

  • A 是字符串标量。

  • B 是 1×任意长度的双精度值向量。

  • C 是 2×2 元胞数组。

值转换

以下函数说明如何转换输入以匹配在 arguments 代码块中指定的类。SpeedEnum 类是为定义第三个输入参数允许的值而创建的枚举类。

function forwardSpeed(a,b,c)
    arguments
        a double
        b char
        c SpeedEnum
    end

    % Function code
    disp(class(a))
    disp(class(b))
    disp(class(c))
end

以下代码定义该枚举类。

classdef SpeedEnum < int32
    enumeration
        Full   (100)
        Half   (50)
        Stop   (0)
    end
end

该函数调用使用的输入值可由 MATLAB 转换为声明的类型。函数中实际的参数类型则显示为输出。

forwardSpeed(int8(4),"A string",'full')
double
char
SpeedEnum

使用验证函数设置具体限制

验证函数可以用更具体的方式限制输入参数。您可以将预定义的验证函数用于许多常见类型的验证,并且可以定义自己的验证函数来满足特定要求。

例如,此函数使用 mustBeNumericmustBeRealmustBeMember 及局部函数 mustBeEqualSize 指定以下验证。

  • 输入 x 必须为任意长度的实数数值行向量。

  • 输入 v 必须为与 x 大小相同的实数数值行向量。

  • 输入 method 必须为字符向量且是三个允许的选项之一。由于 method 指定默认值,此参数是可选的。

function myInterp(x,v,method)
    arguments
        x (1,:) {mustBeNumeric,mustBeReal}
        v (1,:) {mustBeNumeric,mustBeReal,mustBeEqualSize(v,x)}
        method (1,:) char {mustBeMember(method,{'linear','cubic','spline'})} = 'linear'
    end
    % Function code
    ....
end

% Custom validation function
function mustBeEqualSize(a,b)
    % Test for equal size
    if ~isequal(size(a),size(b))
        eid = 'Size:notEqual';
        msg = 'Size of first input must equal size of second input.';
        throwAsCaller(MException(eid,msg))
    end
end

避免在自定义验证函数中使用函数参数验证。如需定义验证函数的详细信息,或要查看预定义验证函数列表,请参阅参数验证函数

参数的种类

函数参数验证可以声明四种参数。函数可以定义四种参数中的任何一种,但参数必须按照以下顺序定义:

  1. 必需位置参数

  2. 可选位置参数

  3. 重复位置参数

  4. 可选名称-值参数

必需和可选位置参数

位置参数必须以特定顺序传递给函数。参数列表中传递的值的位置必须对应于参数在 arguments 代码块中声明的顺序。arguments 代码块中的所有参数名称必须唯一。

调用函数时,arguments 代码块中的位置参数为必需,除非此参数定义了默认值。在参数声明中指定默认值会使位置参数成为可选参数,因为 MATLAB 可以在函数调用中没有传递值时使用默认值。

默认值可以是常量,也可以是结果满足参数声明的表达式。表达式可以引用在 arguments 代码块中在该表达式之前声明的参数,但无法引用在它后面声明的参数。

MATLAB 仅在函数调用不包含某参数时才计算其默认值表达式。

所有可选参数都必须位于 arguments 代码块中的所有必需参数后。例如,在此参数代码块中,maxvalminval 具有默认值,因此是可选的。

function myFunction(x,y,maxval,minval)
    arguments
        x (1,:) double
        y (1,:) double
        maxval (1,1) double = max(max(x),max(y))
        minval (1,1) double = min(min(x),min(y))
    end

    % Function code
    ....
end

您可以使用以下任意语法调用此函数:

myFunction(x,y,maxval,minval) 
myFunction(x,y,maxval) 
myFunction(x,y) 

如果必须在函数调用中填充某可选位置参数的位置以标识其后的参数,则该可选位置参数变为必需参数。在上述实例中,这相当于:如果要指定 minval 的值,必须指定 maxval 的值。

被忽略位置参数

MATLAB 允许您通过传递波浪号字符 (~) 代替参数来忽略输入参数。您可以通过在参数代码块中添加波浪号字符 (~) 来定义一个忽略未使用位置参数的函数,添加字符的位置对应于该参数在函数签名中的位置。为函数签名中的每个被忽略参数添加一个波浪号字符 (~)。

被忽略参数不能有默认值,也不能指定类、大小或验证函数。

波浪号字符 (~) 被视为可选输入参数,除非它后跟必需位置参数。例如,在此函数中,波浪号字符 (~) 代表一个可选参数。

function c = f(~)
    arguments
        ~
    end

    % Function code
end

您可以不带参数调用此函数。

c = f 

您也可以带一个参数调用此函数。

c = f(2)

在以下函数中,波浪号字符 (~) 代表一个必需参数。

function c = f(~,x)
    arguments
        ~
        x
    end

    % Function code
    ...
end

对此函数的调用必须包含两个参数。

c = f(2,3)

有关调用具有被忽略输入的函数的详细信息,请参阅忽略函数定义中的输入

重复参数

重复参数是可以重复指定为输入参数的位置参数。在包含 Repeating 属性的 arguments 代码块中声明重复参数。

arguments (Repeating)
    arg1
    arg2
    ...
end

函数只能有一个 Repeating arguments 代码块,其中可以包含一个或多个重复参数。

如果函数定义了 Repeating arguments 代码块,则调用该函数时,此代码块中的参数可以一次也不出现,也可以全体出现一次或多次。如果对函数的调用包含重复参数,则每次重复都必须包含 Repeating arguments 代码块中的所有参数。

例如,如果 Repeating arguments 代码块定义参数 xy,则每次重复必须同时包含 xy

重复参数不能指定默认值,因此不能为可选项。但是,您可以不带任何重复参数调用函数。

重复参数在函数中的声明顺序必须在位置参数之后、名称-值参数之前。您不能在 Repeating 代码中指定名称-值参数。有关名称-值参数的信息,请参阅名称-值参数

在函数中,每个重复参数构成一个元胞数组,其中包含的元素数等于在函数调用中传递的重复次数。验证应用于该元胞数组的每个元素。如果调用函数时该参数的出现次数为零,则元胞数组的大小为 1×0。也就是说,它为空。

例如,以下函数声明一个重复参数代码块,其中包含三个参数 xyoption

function [xCell,yCell,optionCell] = fRepeat(x,y,option)
    arguments (Repeating)
        x double
        y double
        option {mustBeMember(option,["linear","cubic"])}
    end
    
    % Function code
    % Return cell arrays
    xCell = x;
    yCell = y;
    optionCell = option;
end

调用此函数时,您可以不带输入,也可以将三个输入重复多次。MATLAB 为每个参数创建一个元胞数组,其中包含为该参数传递的所有值。以下对 fRepeat 的调用将这三个重复参数全体传递了两次。

[xCell,yCell,optionCell] = fRepeat(1,2,"linear",3,4,"cubic")
xCell =

  1×2 cell array

    {[1]}    {[3]}


yCell =

  1×2 cell array

    {[2]}    {[4]}


optionCell =

  1×2 cell array

    {["linear"]}    {["cubic"]}

以下函数声明 Repeating arguments 代码块,从而允许重复输入参数 xy。在函数体中,指定为重复参数的值包含在元胞数组 xy 中。此示例交错 xy 中的值,以匹配 plot 函数的必需输入:plot(x1,y1,…)

function myPlotRepeating(x,y)
    arguments (Repeating)
        x (1,:) double
        y (1,:) double
    end

    % Function code
    % Interleave x and y
    z = reshape([x;y],1,[]);

    % Call plot function
    if ~isempty(z)
        plot(z{:});
    end
end

使用重复的输入参数对来调用此函数。

x1 = 1:10;
y1 = sin(x1);
x2 = 0:5;
y2 = sin(x2);
myPlotRepeating(x1,y1,x2,y2)

避免对重复参数使用 varargin

不建议将 varargin 与使用参数验证的函数结合使用。如果 varargin 在重复参数代码块中具有大小或类方面的限制,则这些限制将应用于 varargin 中的所有值。

如果您使用 varargin 支持原有代码,它必须为 Repeating arguments 代码块中的唯一参数。

例如,此函数定义两个必需位置参数,并将 varargin 定义为重复参数。

function f(a, b, varargin)
    arguments
        a uint32
        b uint32
    end
    arguments (Repeating)
        varargin
    end
    
    % Function code
    ...
end

名称-值参数

名称-值参数将名称与传递给函数的值相关联。名称-值参数:

  • 可以按任何顺序传递给函数

  • 始终为可选

  • 必须在所有位置参数和重复参数之后声明

  • 不能出现在使用 Repeating 属性的 arguments 代码块中

  • 必须使用唯一名称,即便使用多个名称-值结构体时也是如此

  • 不能与位置参数同名

使用圆点表示法在 arguments 代码块中声明名称-值参数以定义结构体的字段。例如,名为 NameValueArgs 的结构体定义两个名称-值参数 Name1Name2。您可以使用任何有效的 MATLAB 标识符作为结构体名称。

arguments
    NameValueArgs.Name1
    NameValueArgs.Name2
end

结构体名称必须出现在函数签名中。

function myFunction(NameValueArgs)

使用名称-值结构体中的字段名称调用该函数。

myFunction(Name1=value1,Name2=value2)

在 R2021a 之前,将名称作为字符串或字符向量传递,并以逗号分隔名称和值。这两种语法在以后的版本中都有效。

函数签名中使用的结构体名称是函数工作区中包含传递给该函数的名称和值的结构体的名称。

function result = myFunction(NameValueArgs)
    arguments
        NameValueArgs.Name1
        NameValueArgs.Name2
    end

    % Function code
    result = NameValueArgs.Name1 * NameValueArgs.Name2;
end
r = myFunction(Name1=3,Name2=7)
r =

    21

当不存在多义性时,名称-值参数支持部分名称匹配。例如,将 LineWidthLineStyle 定义为其两个名称-值参数的函数接受 LineWLineS,但使用 Line 会导致错误。一般情况下,推荐使用全名,以提高代码可读性和避免意外行为。

名称-值参数的默认值

您可以为每个名称指定一个默认值。如果没有指定默认值,并且调用函数时不带该名称-值参数,则该字段不存在于名称-值结构体中。如果没有向函数传递名称-值参数,MATLAB 仍会创建结构体,但它没有字段。

要确定在函数调用中传递了哪些名称-值参数,请使用 isfield 函数。

例如,以下函数定义两个必需位置参数(widthheight)和两个名称-值参数(LineStyleLineWidth)。在此示例中,options 结构体有两个字段(LineStyleLineWidth),其中包含默认值或在调用函数时指定为名称-值参数的值。

function myRectangle(width,height,options)
    arguments
        width double
        height double
        options.LineStyle (1,1) string = "-"
        options.LineWidth (1,1) {mustBeNumeric} = 1
    end

    % Function code
    ...
end

所有以下语法均为调用此函数的有效方式。

myRectangle(4,5)
myRectangle(4,5,LineStyle=":",LineWidth=2)
myRectangle(4,5,LineWidth=2,LineStyle=":")
myRectangle(4,5,LineStyle=":")
myRectangle(4,5,LineWidth=2)

在 R2021a 之前,将名称作为字符串或字符向量传递,并以逗号分隔名称和值。例如:

myRectangle(4,5,"LineStyle",":","LineWidth",2)
myRectangle(4,5,"LineWidth",2,"LineStyle",":")

同时使用重复参数和名称-值参数

如果函数定义了重复参数,则您必须在重复参数代码块之后另加一个 arguments 代码块来声明名称-值参数。例如,此函数接受两个重复参数 xy。在指定 xy 的所有重复项后,您可以指定一个名称-值参数,它将值 linlog 赋给 PlotType 名称。

要确定函数调用是否包含 PlotType 参数,请使用 isfield 函数检查 scale 结构体中是否存在 PlotType 字段。

function myLinLog(x,y,scale)
    arguments(Repeating)
        x (1,:) double
        y (1,:) double
    end
    arguments
        scale.PlotType (1,1) string
    end
    z = reshape([x;y],1,[]);
    if isfield(scale,"PlotType")
        if scale.PlotType == "lin"
            plot(z{:})
        elseif scale.PlotType =="log"
            loglog(z{:})
        end
    end
end

以带或不带名称-值参数的方式调用此函数。

myLinLog(1:5,1:5)
myLinLog(1:5,1:5,1:10,1:100:1000)
myLinLog(1:5,1:5,1:10,1:100:1000,PlotType="log")

在 R2021a 之前,将名称作为字符串或字符向量传递,并以逗号分隔名称和值。例如:

myLinLog(1:5,1:5,1:10,1:100:1000,"PlotType","log")

多个名称-值结构体

函数参数代码块可以包含多个名称-值结构体。但是,字段名称在所有结构体中必须唯一。此函数有两个名称-值结构体:lineOptionsfillOptions。这些结构体不能有相同的字段名称。

myRectangle 函数中的参数是:

  • widthheightdouble 类型的必需位置参数。

  • lineOptions.LineStyle 是标量字符串,默认值为 "-"

  • lineOptions.LineWidth 是标量数值,默认值为 1

  • fillOptions.Color 是字符串。

  • fillOptions.Pattern 对其值没有任何限制。

function myRectangle(width,height,lineOptions,fillOptions)
    arguments
        width double
        height double
        lineOptions.LineStyle (1,1) string = "-"
        lineOptions.LineWidth (1,1) {mustBeNumeric} = 1
        fillOptions.Color string
        fillOptions.Pattern
    end

    % Function Code
    ...
end

名称-值参数的稳健处理

在函数中实现名称-值参数的最佳做法是在参数块中定义它们。使用参数块就无需编写自己的代码来解析名称-值参数,参数块还有助于为 R2021a 中引入的 "name",value 语法和 name=value 语法实现稳健的参数解析。

强制应用有效名称

在参数块中定义名称-值参数可确保名称是有效的标识符。这还有助于确保您的参数同时适用 "name",valuename=value 语法。例如,使用无效标识符的名称-值参数用在逗号分隔语法中是没问题的:

myFunction(data,"allow-empty",true)
但是,使用 allow-empty=true 语法执行同一调用则会引发错误。在参数块中定义名称-值参数可确保您定义的名称是有效的 MATLAB 变量名称,并且符合 name=value 语法。

避免因文本输入而导致的意外结果

同时包含可选文本输入和名称-值参数的函数存在 MATLAB 误将文本输入解释为名称-值参数名称的风险。以下函数包括两个可选的文本输入和一个名称-值参数。

function mySignal(tag,unit,opts)
    arguments
        tag = "0"
        unit = "ampere"
        opts.Magnifier {mustBeMember{opts.Magnifier,["small","medium","big"]}}
    end
end
用户输入以下函数调用是为了将 tag 的值设置为 "Mag" 并将 unit 的值设置为 "coulomb"
mySignal("Mag","coulomb")
但是,MATLAB 通过部分匹配将 "Mag" 解析为名称-值参数 Magnifer"coulomb" 不是该名称的有效值,因此函数出错。

避免这种情况的一种方法是通过删除 tag 的默认值,使其成为必需的参数:

function mySignal(tag,unit,opts)
    arguments
        tag
        unit = "ampere"
        opts.Magnifier {mustBeMember{opts.Magnifier,["small","medium","big"]}}
    end
end
由于 MATLAB 不会将必需的输入解析为名称-值参数,同一函数调用现在将值 tag 设置为 "Mag",并且不会出错。

另一种方法是将所有三个输入都作为名称-值参数。这有助于避免用户在指定输入时出错,因为每个值都与一个名称相关联,并且用户指定输入的顺序不会影响最终结果。

基于类属性的名称-值参数

MATLAB 提供了一个方便的函数语法,允许您使用类的公共属性作为名称-值参数的名称。要将类定义的所有可设置属性(即具有公共 SetAccess 的所有属性)指定为名称-值参数,请在 arguments 代码块中使用以下语法:

structName.?ClassName

一个函数只能使用一次 "structName.? ClassName" 语法。因此,即便使用不同的类和结构体名称,一个函数也只能定义一个从类中获取字段名称的名称-值结构体。

如果类通过属性验证来限制可以赋给属性的值,则函数会将验证应用于单独的名称-值参数。有关属性验证的信息,请参阅验证属性值

例如,此函数有两个必需参数 xy,并且接受 matlab.graphics.chart.primitive.Bar 类的任何公共属性的名称和值。

function myBar(x,y,propArgs)
    arguments
        x (:,:) double
        y (:,:) double
        propArgs.?matlab.graphics.chart.primitive.Bar
    end
    propertyCell = namedargs2cell(propArgs);
    bar(x,y,propertyCell{:})
end

使用必需输入以及任何可设置属性的名称-值对组来调用此函数。

x = [1,2,3;4,5,6];
y = x.^2;
myBar(x,y)
myBar(x,y,FaceColor="magenta",BarLayout="grouped")

在 R2021a 之前,将名称作为字符串或字符向量传递,并以逗号分隔名称和值。例如:

myBar(x,y,"FaceColor","magenta","BarLayout","grouped")

覆盖特定属性

您可以通过在参数代码块中用特定名称-值参数重新定义属性名称来覆盖类属性验证。

structName.?ClassName
structName.PropertyName (dim1,dim2,...) ClassName {fcn1,fcn2,...}

特定名称-值参数验证将覆盖类为单独指定的属性名称定义的验证。

例如,以下函数将名称-值参数定义为 matlab.graphics.chart.primitive.Bar 类的属性。该函数还覆盖属性名称 FaceColor 以仅允许这些特定值:redblue

matlab.graphics.chart.primitive.Bar 类的 FaceColor 的默认值不是允许值(redblue)。因此,覆盖声明必须赋予一个默认值,该默认值满足 mustBeMember 验证函数施加的限制。也就是说,默认值必须为 redblue

此函数使用 namedargs2cell 函数将名称-值结构体转换为名称与值相互交错的元胞数组。

function myBar(x,y,propArgs)
    arguments
        x (:,:) double
        y (:,:) double
        propArgs.?matlab.graphics.chart.primitive.Bar
        propArgs.FaceColor {mustBeMember(propArgs.FaceColor,{'red','blue'})} = "blue"
    end
    propertyCell = namedargs2cell(propArgs);
    bar(x,y,propertyCell{:})
end

使用两个必需参数 xy 调用函数。您还可以视需要传递 bar 函数支持的任何名称-值对组以及 FaceColor 的值,该值可以是 redblueFaceColor 不允许使用其他值。

x = [1,2,3;4,5,6];
y = x.^2;
myBar(x,y)
myBar(x,y,FaceColor="red",BarLayout="grouped")

类方法中的参数验证

在公共方法中,对方法输入参数进行验证很有用,因为对方法的调用可能不是源于类代码。您可以在具体类方法中使用函数参数验证,包括在抽象类中定义的具体方法。但是,抽象方法(并非由类实现的方法)无法定义 arguments 代码块。有关类方法的信息,请参阅方法抽象类和类成员

如果 classdef 文件包含在单独文件中定义的方法的方法原型,请在定义该方法的单独文件中包含 arguments 代码块。有关在单独的文件中定义方法的详细信息,请参阅在单独文件中定义方法

子类方法不继承函数参数验证。在覆盖超类方法的子类方法中,您可以向子类方法添加与在超类方法中使用的相同参数验证。

句柄类析构函数方法无法使用参数验证。在包含 arguments 代码块的句柄子类中,名为 delete 的方法不会被视为析构函数。(换句话说,在销毁对象时,MATLAB 不调用它。)有关类析构函数方法的详细信息,请参阅句柄类析构函数

参数验证的顺序

在调用函数时,MATLAB 按照输入参数在 arguments 代码块中的声明顺序从上往下验证输入参数。上一个参数完全验证后,才会继续验证下一个参数。这就确保引用较早声明的参数时,使用的是经过验证的值。在第一次验证失败时,函数会引发错误。

经过验证的值可能不同于调用函数时作为输入传递的原始值。例如,此函数将输入声明为类 uint32 值。第三个输入声明指定了一个默认值,该值等于前两个输入的乘积。

function c = f(a, b,c)
    arguments
        a uint32
        b uint32
        c uint32 = a .* b
    end

    % Function code
    ...
end

如果使用其他数值类(例如 double)的输入来调用函数,则输入会被转换为 uint32

c = f(1.8,1.5)

由于在函数调用中没有指定可选输入参数 c,因此在将 ab 转换为 uint32 值后,MATLAB 会计算默认值并将其赋给 c。在本例中,两个输入的转换结果均为值 2。因此,ab 的乘积是 4。

c =

  uint32

   4

如果您为第三个输入指定值,则该函数会为 c 赋值,并且不会计算默认值表达式。

c = f(1.8,1.5,25)
c =

  uint32

   25

避免类和大小转换

在验证过程中,MATLAB 在调用任何验证函数之前,会先应用类验证,然后应用大小验证。如果默认值用于函数调用中省略的可选输入,则在应用验证过程中的任何步骤之前,会先将该值赋给参数。

当传递给函数的参数值与验证所要求的类和大小不匹配时,MATLAB 会尽可能将该值转换为声明的类和大小。然而,转换可能不是所需的行为。

以下是 MATLAB 可以执行的一些转换示例。

为了满足数值类限制,支持以下功能:

  • char 值可以转换为其 Unicode® 数值。

  • string 可以转换为数字或 NaN(如果字符串不是单个数字的表示形式)。

为了满足大小限制,支持以下功能:

  • 标量扩展可以将大小从标量变为非标量。

  • 列向量可以转换为行向量。

要从输入参数验证中去除 MATLAB 执行的标准转换,请使用验证函数,而不是类和大小限制。对验证函数的调用不会返回值,也无法更改输入参数的值。

例如,此函数将第一个输入限制为 double 类的任意大小的二维数组。第二个输入必须为任何类的 5×3 数组。

function f(a, b)
    arguments
        a (:,:) double
        b (5,3)
    end

    % Function code
    ...
end

由于存在标准 MATLAB 类型转换和标量扩展,您可以使用以下输入调用此函数,而不会收到验证错误。

f('character vector',144)

默认情况下,MATLAB 将字符向量的元素转换为其等效数值,并应用标量扩展以基于标量值 144 创建一个 5×3 数组。

使用专用验证函数可以提供更具体的输入参数验证。例如,此函数定义专用验证函数,用于代替第一个和第二个参数的类和大小设定。这些局部函数帮助您避免输入值转换。

  • mustBeOfClass 将输入限制为特定类,不允许转换或子类化。要了解相关函数的信息,请参阅 mustBeA

  • mustBeEqualSize 限制两个输入的大小相等,不允许标量扩展。要了解相关函数的信息,请参阅 mustBeScalarOrEmpty

  • mustBeDims 将输入限制为具有指定的维度,不允许转置或标量扩展。要了解相关函数的信息,请参阅 mustBeVector

function fCustomValidators(a,b)
    arguments
        a {mustBeOfClass(a,'double'), mustBeDims(a,2)}
        b {mustBeEqualSize(b,a)}
    end

    % Function code
    ...
end

% Custom validator functions
function mustBeOfClass(input,className)
    % Test for specific class name
    cname = class(input);
    if ~strcmp(cname,className)
        eid = 'Class:notCorrectClass';
        msg = ['Input must be of class ', cname];
        throwAsCaller(MException(eid,msg))
    end
end

function mustBeEqualSize(a,b)
    % Test for equal size
    if ~isequal(size(a),size(b))
        eid = 'Size:notEqual';
        msg = 'Inputs must have equal size.';
        throwAsCaller(MException(eid,msg))
    end
end

function mustBeDims(input,numDims)
    % Test for number of dimensions    
    if ~isequal(length(size(input)),numDims)
        eid = 'Size:wrongDimensions';
        msg = ['Input must have dimensions: ',num2str(numDims)];
        throwAsCaller(MException(eid,msg))
    end
end

mustBeOfClass 函数通过要求与类名称匹配来实现严格的类匹配。更一般的方法是使用 isa 函数来同时匹配指定类的子类。

mustBeEqualSizemustBeDims 函数对输入参数执行严格的声明。

fCustomValidators('character vector',144)
Invalid input argument at position 1. Input must be of class double

在此调用中,第一个输入的维数是错误的,因此验证函数返回自定义错误消息。

fCustomValidators(ones(2,2,4),144)
Invalid input argument at position 1. Input must have 2 dimensions

mustBeEqualSize 验证函数将第二个输入限制为特定维度,如错误消息所示。

fCustomValidators(ones(2,2),144)
Invalid input argument at position 2. Input must be of size [5  3]

要了解相关预定义验证函数的信息,请参阅 mustBeAmustBeFloatmustBeVector

参数验证中的 nargin

nargin 函数针对当前正在执行的函数,返回函数调用中给定函数输入参数的数目。使用函数参数验证时,函数内 nargin 返回的值是调用函数时提供的位置参数的数量。

重复参数是位置参数,因此调用时传递给函数的重复参数的个数将计入 nargin 返回的值。

nargin 返回的值不包括未包含在函数调用中的可选参数。此外,nargin 不对任何名称-值参数进行计数。

使用 nargin 确定在调用时是否将可选位置参数传递给函数。例如,此函数声明三个位置参数和一个名称-值参数。函数通过以下方式确定在调用时传递哪些参数。

  • nargin 通过 switch 代码块确定是否将可选位置参数 c 传递给函数。

  • isfield 确定是否将 Format 的名称-值参数传递给函数。

function result = fNargin(a,b,c,namedargs)
    arguments
        a (1,1) double
        b (1,1) double
        c (1,1) double = 1
        namedargs.Format (1,:) char
    end

    % Function code
    switch nargin
        case  2
            result = a + b;
        case 3
            result = a^c + b^c;
    end
    if isfield(namedargs,"Format")
        format(namedargs.Format);
    end
end

在此函数调用中,nargin 的值是 2

result = fNargin(3,4)
result =

     7

在此函数调用中,nargin 的值是 3

result = fNargin(3,4,7.62)
result =

   4.3021e+04

在此函数调用中,nargin 的值是 3:

result = fNargin(3,4,7.62,Format="bank")
result =

      43020.56

变量和函数访问的限制

arguments 代码块存在于函数的工作区中。使用 import 命令添加到函数作用域的任何包、类或函数都将添加到 arguments 代码块的作用域中。

对验证函数和默认值表达式可见的变量只有已声明的输入变量。在以下函数中,c 的默认值派生自 ab

function c = f(a,b,c)
    arguments
        a uint32
        b uint32
        c uint32 = a * b
    end
 
    % Function code
    ...
end

但是,您无法引用尚未在 arguments 代码块中声明的输入变量。例如,在上述函数中对参数 a 使用以下声明是无效的,因为 bc 尚未声明。

arguments
    a uint32 = b * c
    b uint32
    c uint32
end

参数验证表达式只能引用此前声明过(因此经过验证)的参数。名称-值参数的验证函数和默认值无法访问其他名称-值参数。

arguments 代码块中函数的限制

对此前所声明参数的任何引用必须在验证函数和默认值的文本中可见。为了确保代码透明,请不要使用与函数工作区交互的函数。尤其不要在 arguments 代码块中使用嵌套函数或下表中列出的任何函数。

assigninbuiltinclear
dbstackevalevalc
evalinexistfeval
inputinputnameload
narginnarginchknargoutchk
savewhoswho

这些限制仅适用于 arguments 代码块,对函数体中的变量或函数则不适用。

调试参数块

在参数块内部调试时,工作区为只读。这意味着可以检查工作区并查看赋给变量的值。但是,当工作区为只读时,无法创建新变量或更改赋给现有变量的值。一旦调试器位于参数块之外,就可以再次创建或编辑变量。

另请参阅

|

相关主题