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 - 输入必须为元胞数组。

  • 用户定义的类

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

示例:基本参数验证

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 元胞数组。

验证函数

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

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

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

示例:使用验证函数设置特定限制

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

例如,此函数使用 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.';
        error(eid,msg)
    end
end

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

默认值

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

注意

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

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

转换为声明的类和大小

类验证和大小验证都可以更改参数的值。以下是 MATLAB 可以执行的一些转换示例。

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

  • char 值可以转换为 string 值。

  • single 值可以转换为 double

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

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

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

因此,函数体中经过验证的值可能不同于调用函数时传递的值。有关类转换的详细信息,请参阅Implicit Class Conversion。为了避免验证过程中的类和大小转换,请改用参数验证函数。有关详细信息,请参阅Use Validation Functions to Avoid Unwanted Class and Size Conversions

示例:值转换

以下函数说明如何转换输入以匹配在 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

输出参数验证

从 R2022b 开始,可以对输出参数使用参数验证。与输入参数类似,您可以验证输出参数的类和大小,还可以应用验证函数。但是,您无法为输出参数指定默认值,也无法引用以前声明的参数。输出参数验证始终是可选的。添加输出参数验证有助于提高代码的可读性,并在可能随时间而变化的代码中使输出保持一致。

必须使用单独的 arguments 块来验证输入和输出参数。在 arguments 语句后定义参数块 (Input)(Output) 的类型。如果同时使用 (Input)(Output) 参数块,则 (Output) 块必须跟在 (Input) 块后。如果没有指定类型,则 MATLAB 假定该块包含输入参数。

有关详细信息,请参阅 arguments

示例:验证输出参数

从 R2022b 开始,可以对输出参数使用参数验证。

例如,此函数使用单独的参数块验证三个输入参数和输出参数的大小和类。请注意,(Input) 块必须在 (Output) 块之前。

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

    arguments (Output)
        out (1,:) double
    end

    % Function code
    ...
end

参数的种类

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

参数类型其他信息

1.必需位置参数

验证必需和可选位置参数

2.可选位置参数

3.重复位置参数

验证重复参数

4.可选名称-值参数

验证名称-值参数

参数验证的顺序

在调用函数时,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

变量和函数访问的限制

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 代码块,对函数体中的变量或函数则不适用。

调试参数块

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

另请参阅

|

相关主题