函数参数验证
参数验证简介
函数参数验证是一种对函数输入参数声明特定限制的方法。使用参数验证,您可以约束函数输入值的类、大小和其他方面,而无需在函数体中编写代码来执行这些测试。
函数参数验证是声明性的,这使得 MATLAB® 桌面工具能够通过检查特定代码块来提取关于函数的信息。通过声明输入参数的要求,您可以消除繁琐的参数检查代码,并提高代码的可读性、稳健性和可维护性。
函数参数验证语法简化了定义可选参数、重复参数和名称-值参数的过程。该语法还使您能够以一致的方式定义默认值。
何时使用参数验证
在函数定义中,您可以选择是否使用函数参数验证。如果函数可由任何代码调用,并且在执行函数代码之前必须确定输入的有效性,则参数验证能起到很大帮助。对于那些为他人使用而设计的函数,如能对参数输入施加适当限制,并允许基于函数输入返回特定错误消息,也可使用户受益。
何时不需要验证
在局部和私有函数中,以及在私有或受保护方法中,调用方知道输入要求,因此可以使用有效参数调用这些类型的函数。
何时不允许验证
在嵌套函数、抽象方法或句柄类析构函数方法中,不能使用参数验证语法。有关方法中参数验证的详细信息,请参阅类方法中的参数验证。
arguments
代码块语法
函数在以关键字 arguments
和 end
起止的代码块中定义参数验证。如果使用,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
使用验证函数设置具体限制
验证函数可以用更具体的方式限制输入参数。您可以将预定义的验证函数用于许多常见类型的验证,并且可以定义自己的验证函数来满足特定要求。
例如,此函数使用 mustBeNumeric
、mustBeReal
、mustBeMember
及局部函数 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
避免在自定义验证函数中使用函数参数验证。如需定义验证函数的详细信息,或要查看预定义验证函数列表,请参阅参数验证函数。
参数的种类
函数参数验证可以声明四种参数。函数可以定义四种参数中的任何一种,但参数必须按照以下顺序定义:
必需位置参数
可选位置参数
重复位置参数
可选名称-值参数
必需和可选位置参数
位置参数必须以特定顺序传递给函数。参数列表中传递的值的位置必须对应于参数在 arguments
代码块中声明的顺序。arguments
代码块中的所有参数名称必须唯一。
调用函数时,arguments
代码块中的位置参数为必需,除非此参数定义了默认值。在参数声明中指定默认值会使位置参数成为可选参数,因为 MATLAB 可以在函数调用中没有传递值时使用默认值。
默认值可以是常量,也可以是结果满足参数声明的表达式。表达式可以引用在 arguments
代码块中在该表达式之前声明的参数,但无法引用在它后面声明的参数。
MATLAB 仅在函数调用不包含某参数时才计算其默认值表达式。
所有可选参数都必须位于 arguments
代码块中的所有必需参数后。例如,在此参数代码块中,maxval
和 minval
具有默认值,因此是可选的。
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
代码块定义参数 x
和 y
,则每次重复必须同时包含 x
和 y
。
重复参数不能指定默认值,因此不能为可选项。但是,您可以不带任何重复参数调用函数。
重复参数在函数中的声明顺序必须在位置参数之后、名称-值参数之前。您不能在 Repeating
代码中指定名称-值参数。有关名称-值参数的信息,请参阅名称-值参数。
在函数中,每个重复参数构成一个元胞数组,其中包含的元素数等于在函数调用中传递的重复次数。验证应用于该元胞数组的每个元素。如果调用函数时该参数的出现次数为零,则元胞数组的大小为 1×0。也就是说,它为空。
例如,以下函数声明一个重复参数代码块,其中包含三个参数 x
、y
和 option
。
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
代码块,从而允许重复输入参数 x
和 y
。在函数体中,指定为重复参数的值包含在元胞数组 x
和 y
中。此示例交错 x
和 y
中的值,以匹配 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
的结构体定义两个名称-值参数 Name1
和 Name2
。您可以使用任何有效的 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
当不存在多义性时,名称-值参数支持部分名称匹配。例如,将 LineWidth
和 LineStyle
定义为其两个名称-值参数的函数接受 LineW
和 LineS
,但使用 Line
会导致错误。一般情况下,推荐使用全名,以提高代码可读性和避免意外行为。
名称-值参数的默认值
您可以为每个名称指定一个默认值。如果没有指定默认值,并且调用函数时不带该名称-值参数,则该字段不存在于名称-值结构体中。如果没有向函数传递名称-值参数,MATLAB 仍会创建结构体,但它没有字段。
要确定在函数调用中传递了哪些名称-值参数,请使用 isfield
函数。
例如,以下函数定义两个必需位置参数(width
和 height
)和两个名称-值参数(LineStyle
和 LineWidth
)。在此示例中,options
结构体有两个字段(LineStyle
和 LineWidth
),其中包含默认值或在调用函数时指定为名称-值参数的值。
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
代码块来声明名称-值参数。例如,此函数接受两个重复参数 x
和 y
。在指定 x
和 y
的所有重复项后,您可以指定一个名称-值参数,它将值 lin
或 log
赋给 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")
多个名称-值结构体
函数参数代码块可以包含多个名称-值结构体。但是,字段名称在所有结构体中必须唯一。此函数有两个名称-值结构体:lineOptions
和 fillOptions
。这些结构体不能有相同的字段名称。
myRectangle
函数中的参数是:
width
和height
是double
类型的必需位置参数。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",value
和 name=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")
"Mag"
解析为名称-值参数 Magnifer
。"coulomb"
不是该名称的有效值,因此函数出错。避免这种情况的一种方法是通过删除 tag
的默认值,使其成为必需的参数:
function mySignal(tag,unit,opts) arguments tag unit = "ampere" opts.Magnifier {mustBeMember{opts.Magnifier,["small","medium","big"]}} end end
tag
设置为 "Mag"
,并且不会出错。另一种方法是将所有三个输入都作为名称-值参数。这有助于避免用户在指定输入时出错,因为每个值都与一个名称相关联,并且用户指定输入的顺序不会影响最终结果。
基于类属性的名称-值参数
MATLAB 提供了一个方便的函数语法,允许您使用类的公共属性作为名称-值参数的名称。要将类定义的所有可设置属性(即具有公共 SetAccess
的所有属性)指定为名称-值参数,请在 arguments
代码块中使用以下语法:
structName.?ClassName
一个函数只能使用一次 "structName
.?
ClassName
" 语法。因此,即便使用不同的类和结构体名称,一个函数也只能定义一个从类中获取字段名称的名称-值结构体。
如果类通过属性验证来限制可以赋给属性的值,则函数会将验证应用于单独的名称-值参数。有关属性验证的信息,请参阅验证属性值。
例如,此函数有两个必需参数 x
和 y
,并且接受 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
以仅允许这些特定值:red
或 blue
。
matlab.graphics.chart.primitive.Bar
类的 FaceColor
的默认值不是允许值(red
或 blue
)。因此,覆盖声明必须赋予一个默认值,该默认值满足 mustBeMember
验证函数施加的限制。也就是说,默认值必须为 red
或 blue
。
此函数使用 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
使用两个必需参数 x
和 y
调用函数。您还可以视需要传递 bar 函数支持的任何名称-值对组以及 FaceColor
的值,该值可以是 red
或 blue
。FaceColor
不允许使用其他值。
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
,因此在将 a
和 b
转换为 uint32
值后,MATLAB 会计算默认值并将其赋给 c
。在本例中,两个输入的转换结果均为值 2。因此,a
和 b
的乘积是 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
函数来同时匹配指定类的子类。
mustBeEqualSize
和 mustBeDims
函数对输入参数执行严格的声明。
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]
要了解相关预定义验证函数的信息,请参阅 mustBeA
、mustBeFloat
和 mustBeVector
。
参数验证中的 nargin
nargin
函数针对当前正在执行的函数,返回函数调用中给定函数输入参数的数目。使用函数参数验证时,函数内 nargin
返回的值是调用函数时提供的位置参数的数量。
重复参数是位置参数,因此调用时传递给函数的重复参数的个数将计入 nargin
返回的值。
nargin
返回的值不包括未包含在函数调用中的可选参数。此外,nargin
不对任何名称-值参数进行计数。
使用 nargin
确定在调用时是否将可选位置参数传递给函数。例如,此函数声明三个位置参数和一个名称-值参数。函数通过以下方式确定在调用时传递哪些参数。
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
的默认值派生自 a
和 b
。
function c = f(a,b,c) arguments a uint32 b uint32 c uint32 = a * b end % Function code ... end
但是,您无法引用尚未在 arguments
代码块中声明的输入变量。例如,在上述函数中对参数 a
使用以下声明是无效的,因为 b
和 c
尚未声明。
arguments a uint32 = b * c b uint32 c uint32 end
参数验证表达式只能引用此前声明过(因此经过验证)的参数。名称-值参数的验证函数和默认值无法访问其他名称-值参数。
arguments
代码块中函数的限制
对此前所声明参数的任何引用必须在验证函数和默认值的文本中可见。为了确保代码透明,请不要使用与函数工作区交互的函数。尤其不要在 arguments
代码块中使用嵌套函数或下表中列出的任何函数。
assignin | builtin | clear |
dbstack | eval | evalc |
evalin | exist | feval |
input | inputname | load |
nargin | narginchk | nargoutchk |
save | whos | who |
这些限制仅适用于 arguments
代码块,对函数体中的变量或函数则不适用。
调试参数块
在参数块内部调试时,工作区为只读。这意味着可以检查工作区并查看赋给变量的值。但是,当工作区为只读时,无法创建新变量或更改赋给现有变量的值。一旦调试器位于参数块之外,就可以再次创建或编辑变量。