如何在 MATLAB 中处理函数参数的名称/值对

我有一个函数,它将可选参数作为名称/值对。

function example(varargin)
% Lots of set up stuff
vargs = varargin;
nargs = length(vargs);
names = vargs(1:2:nargs);
values = vargs(2:2:nargs);


validnames = {'foo', 'bar', 'baz'};
for name = names
validatestring(name{:}, validnames);
end


% Do something ...
foo = strmatch('foo', names);
disp(values(foo))
end


example('foo', 1:10, 'bar', 'qwerty')

似乎在提取适当的值方面有很多工作要做(而且它仍然不是特别健壮,再次指定的输入也很糟糕)。有没有更好的方法来处理这些名称/值对?有没有 MATLAB 自带的辅助函数?

50200 次浏览

InputParser 对此有帮助。

我更喜欢像这样的自制锅炉代码:

function TestExample(req1, req2, varargin)
for i = 1:2:length(varargin)
if strcmpi(varargin{i}, 'alphabet')
ALPHA = varargin{i+1};


elseif strcmpi(varargin{i}, 'cutoff')
CUTOFF = varargin{i+1};
%we need to remove these so seqlogo doesn't get confused
rm_inds = [rm_inds i, i+1]; %#ok<*AGROW>


elseif strcmpi(varargin{i}, 'colors')
colors = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'axes_handle')
handle = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'top-n')
TOPN = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'inds')
npos = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'letterfile')
LETTERFILE = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'letterstruct')
lo = varargin{i+1};
rm_inds = [rm_inds i, i+1];
end
end

通过这种方式,我可以模拟“选项”和值对,它们几乎与大多数 Matlab 函数采用参数的方式完全相同。

希望能帮上忙,

威尔

我更喜欢用结构来表示我的选择。这为您提供了一种存储选项和定义选项的简单方法。此外,整个事情变得相当紧凑。

function example(varargin)


%# define defaults at the beginning of the code so that you do not need to
%# scroll way down in case you want to change something or if the help is
%# incomplete
options = struct('firstparameter',1,'secondparameter',magic(3));


%# read the acceptable names
optionNames = fieldnames(options);


%# count arguments
nArgs = length(varargin);
if round(nArgs/2)~=nArgs/2
error('EXAMPLE needs propertyName/propertyValue pairs')
end


for pair = reshape(varargin,2,[]) %# pair is {propName;propValue}
inpName = lower(pair{1}); %# make case insensitive


if any(strcmp(inpName,optionNames))
%# overwrite options. If you want you can test for the right class here
%# Also, if you find out that there is an option you keep getting wrong,
%# you can use "if strcmp(inpName,'problemOption'),testMore,end"-statements
options.(inpName) = pair{2};
else
error('%s is not a recognized parameter name',inpName)
end
end

阅读关于这个问题的 Loren 的博文。不要忘记阅读评论部分...-你会看到有相当多的不同方法对这个主题。它们都可以工作,所以选择一个首选的方法实际上是一个个人品味和可维护性的问题。

我可以对此喋喋不休几个小时,但仍然没有一个良好的格式塔视图一般 Matlab 签名处理。但我有几条建议。

首先,采用自由放任的方法来验证输入类型。相信打电话的人。如果您真的想要强类型测试,那么您需要 Java 这样的静态语言。试着在 Matlab 的任何地方强制执行类型安全,你最终会得到很大一部分 LOC 和执行时间用于运行时类型测试和用户领域的强制,这交易了 Matlab 的大量功能和开发速度。我可是吃了不少苦头才知道的。

对于 API 签名(打算从其他函数而不是从命令行调用的函数) ,可以考虑使用单个 Args 参数而不是 varargin。然后,它可以在多个参数之间传递,而无需将其转换为用逗号分隔的 varargin 签名列表。结构,就像乔纳斯说的,非常方便。在 structs 和 n-by-2{ name,value; ... }单元格之间也有一个很好的同构,您可以设置一对函数,在函数内部将它们转换为它想在内部使用的任何函数。

function example(args)
%EXAMPLE
%
% Where args is a struct or {name,val;...} cell array

无论是使用 inputParser 还是像这些示例一样使用自己的 name/val 解析器,都要将其打包到一个单独的标准函数中,您将从具有 name/val 签名的函数的顶部调用该函数。让它接受数据结构中的默认值列表,这样写出来就方便了,而且参数解析调用看起来有点像函数签名声明,这有助于提高可读性,并避免复制粘贴样板代码。

下面是解析调用可能的样子。

function out = my_example_function(varargin)
%MY_EXAMPLE_FUNCTION Example function


% No type handling
args = parsemyargs(varargin, {
'Stations'  {'ORD','SFO','LGA'}
'Reading'   'Min Temp'
'FromDate'  '1/1/2000'
'ToDate'    today
'Units'     'deg. C'
});
fprintf('\nArgs:\n');
disp(args);


% With type handling
typed_args = parsemyargs(varargin, {
'Stations'  {'ORD','SFO','LGA'}     'cellstr'
'Reading'   'Min Temp'              []
'FromDate'  '1/1/2000'              'datenum'
'ToDate'    today                   'datenum'
'Units'     'deg. C'                []
});
fprintf('\nWith type handling:\n');
disp(typed_args);


% And now in your function body, you just reference stuff like
% args.Stations
% args.FromDate

这里有一个函数用来实现 name/val 解析。您可以将它挖空,并用 inputParser、您自己的类型约定等替换它。我认为 n-by-2单元格约定使得源代码具有很好的可读性; 请考虑保留这一点。在接收代码中处理结构通常更方便,但是使用表达式和文字构造 n-by-2单元格更方便。(结构要求在每一行中使用“ ,...”连续,并保护单元格值不扩展为非标量结构。)

function out = parsemyargs(args, defaults)
%PARSEMYARGS Arg parser helper
%
% out = parsemyargs(Args, Defaults)
%
% Parses name/value argument pairs.
%
% Args is what you pass your varargin in to. It may be
%
% ArgTypes is a list of argument names, default values, and optionally
% argument types for the inputs. It is an n-by-1, n-by-2 or n-by-3 cell in one
% of these forms forms:
%   { Name; ... }
%   { Name, DefaultValue; ... }
%   { Name, DefaultValue, Type; ... }
% You may also pass a struct, which is converted to the first form, or a
% cell row vector containing name/value pairs as
%   { Name,DefaultValue, Name,DefaultValue,... }
% Row vectors are only supported because it's unambiguous when the 2-d form
% has at most 3 columns. If there were more columns possible, I think you'd
% have to require the 2-d form because 4-element long vectors would be
% ambiguous as to whether they were on record, or two records with two
% columns omitted.
%
% Returns struct.
%
% This is slow - don't use name/value signatures functions that will called
% in tight loops.


args = structify(args);
defaults = parse_defaults(defaults);


% You could normalize case if you want to. I recommend you don't; it's a runtime cost
% and just one more potential source of inconsistency.
%[args,defaults] = normalize_case_somehow(args, defaults);


out = merge_args(args, defaults);


%%
function out = parse_defaults(x)
%PARSE_DEFAULTS Parse the default arg spec structure
%
% Returns n-by-3 cellrec in form {Name,DefaultValue,Type;...}.


if isstruct(x)
if ~isscalar(x)
error('struct defaults must be scalar');
end
x = [fieldnames(s) struct2cell(s)];
end
if ~iscell(x)
error('invalid defaults');
end


% Allow {name,val, name,val,...} row vectors
% Does not work for the general case of >3 columns in the 2-d form!
if size(x,1) == 1 && size(x,2) > 3
x = reshape(x, [numel(x)/2 2]);
end


% Fill in omitted columns
if size(x,2) < 2
x(:,2) = {[]}; % Make everything default to value []
end
if size(x,2) < 3
x(:,3) = {[]}; % No default type conversion
end


out = x;


%%
function out = structify(x)
%STRUCTIFY Convert a struct or name/value list or record list to struct


if isempty(x)
out = struct;
elseif iscell(x)
% Cells can be {name,val;...} or {name,val,...}
if (size(x,1) == 1) && size(x,2) > 2
% Reshape {name,val, name,val, ... } list to {name,val; ... }
x = reshape(x, [2 numel(x)/2]);
end
if size(x,2) ~= 2
error('Invalid args: cells must be n-by-2 {name,val;...} or vector {name,val,...} list');
end


% Convert {name,val, name,val, ...} list to struct
if ~iscellstr(x(:,1))
error('Invalid names in name/val argument list');
end
% Little trick for building structs from name/vals
% This protects cellstr arguments from expanding into nonscalar structs
x(:,2) = num2cell(x(:,2));
x = x';
x = x(:);
out = struct(x{:});
elseif isstruct(x)
if ~isscalar(x)
error('struct args must be scalar');
end
out = x;
end


%%
function out = merge_args(args, defaults)


out = structify(defaults(:,[1 2]));
% Apply user arguments
% You could normalize case if you wanted, but I avoid it because it's a
% runtime cost and one more chance for inconsistency.
names = fieldnames(args);
for i = 1:numel(names)
out.(names{i}) = args.(names{i});
end
% Check and convert types
for i = 1:size(defaults,1)
[name,defaultVal,type] = defaults{i,:};
if ~isempty(type)
out.(name) = needa(type, out.(name), type);
end
end


%%
function out = needa(type, value, name)
%NEEDA Check that a value is of a given type, and convert if needed
%
% out = needa(type, value)


% HACK to support common 'pseudotypes' that aren't real Matlab types
switch type
case 'cellstr'
isThatType = iscellstr(value);
case 'datenum'
isThatType = isnumeric(value);
otherwise
isThatType = isa(value, type);
end


if isThatType
out = value;
else
% Here you can auto-convert if you're feeling brave. Assumes that the
% conversion constructor form of all type names works.
% Unfortunately this ends up with bad results if you try converting
% between string and number (you get Unicode encoding/decoding). Use
% at your discretion.
% If you don't want to try autoconverting, just throw an error instead,
% with:
% error('Argument %s must be a %s; got a %s', name, type, class(value));
try
out = feval(type, value);
catch err
error('Failed converting argument %s from %s to %s: %s',...
name, class(value), type, err.message);
end
end

在 Matlab,字符串和 datenum 不是一流的类型,这真是太不幸了。

这是我正在试验的解决方案,基于乔纳斯的想法。

function argStruct = NameValuePairToStruct(defaults, varargin)
%NAMEVALUEPAIRTOSTRUCT Converts name/value pairs to a struct.
%
% ARGSTRUCT = NAMEVALUEPAIRTOSTRUCT(DEFAULTS, VARARGIN) converts
% name/value pairs to a struct, with defaults.  The function expects an
% even number of arguments to VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name.)
%
% Examples:
%
% No defaults
% NameValuePairToStruct(struct, ...
%    'foo', 123, ...
%    'bar', 'qwerty', ...
%    'baz', magic(3))
%
% With defaults
% NameValuePairToStruct( ...
%    struct('bar', 'dvorak', 'quux', eye(3)), ...
%    'foo', 123, ...
%    'bar', 'qwerty', ...
%    'baz', magic(3))
%
% See also: inputParser


nArgs = length(varargin);
if rem(nArgs, 2) ~= 0
error('NameValuePairToStruct:NotNameValuePairs', ...
'Inputs were not name/value pairs');
end


argStruct = defaults;
for i = 1:2:nArgs
name = varargin{i};
if ~isvarname(name)
error('NameValuePairToStruct:InvalidName', ...
'A variable name was not valid');
end
argStruct = setfield(argStruct, name, varargin{i + 1});  %#ok<SFLD>
end


end

我个人使用一个自定义函数,该函数派生自许多 Statistics Toolbox 函数(如 kmeans、 pca、 svmtrain、 ttest2、 ...)使用的私有方法

作为一个内部实用程序函数,它在发布过程中多次更改和重命名。根据您的 MATLAB 版本,尝试查找下列文件之一:

%# old versions
which -all statgetargs
which -all internal.stats.getargs
which -all internal.stats.parseArgs


%# current one, as of R2014a
which -all statslib.internal.parseArgs

As with any undocumented function, there are no guarantees and it could be removed from MATLAB in subsequent releases without any notice... Anyways, I believe someone posted an old version of it as Getargs on the File Exchange..

函数将参数作为名称/值对处理,使用一组有效的参数名称及其默认值。它将解析后的参数作为单独的输出变量返回。默认情况下,无法识别的名称/值对会引发错误,但是我们也可以在额外的输出中悄悄地捕获它们。下面是函数描述:

$MATLABROOT\toolbox\stats\stats\+internal\+stats\parseArgs.m

function varargout = parseArgs(pnames, dflts, varargin)
%
% [A,B,...] = parseArgs(PNAMES, DFLTS, 'NAME1',VAL1, 'NAME2',VAL2, ...)
%   PNAMES   : cell array of N valid parameter names.
%   DFLTS    : cell array of N default values for these parameters.
%   varargin : Remaining arguments as name/value pairs to be parsed.
%   [A,B,...]: N outputs assigned in the same order as the names in PNAMES.
%
% [A,B,...,SETFLAG] = parseArgs(...)
%   SETFLAG  : structure of N fields for each parameter, indicates whether
%              the value was parsed from input, or taken from the defaults.
%
% [A,B,...,SETFLAG,EXTRA] = parseArgs(...)
%   EXTRA    : cell array containing name/value parameters pairs not
%              specified in PNAMES.

例如:

function my_plot(x, varargin)
%# valid parameters, and their default values
pnames = {'Color', 'LineWidth', 'LineStyle', 'Title'};
dflts  = {    'r',           2,        '--',      []};


%# parse function arguments
[clr,lw,ls,txt] = internal.stats.parseArgs(pnames, dflts, varargin{:});


%# use the processed values: clr, lw, ls, txt
%# corresponding to the specified parameters
%# ...
end

现在,这个示例函数可以被调用为以下任何一种方式:

>> my_plot(data)                                %# use the defaults
>> my_plot(data, 'linestyle','-', 'Color','b')  %# any order, case insensitive
>> my_plot(data, 'Col',[0.5 0.5 0.5])           %# partial name match

下面是一些无效调用和抛出的错误:

%# unrecognized parameter
>> my_plot(x, 'width',0)
Error using [...]
Invalid parameter name: width.


%# bad parameter
>> my_plot(x, 1,2)
Error using [...]
Parameter name must be text.


%# wrong number of arguments
>> my_plot(x, 'invalid')
Error using [...]
Wrong number of arguments.


%# ambiguous partial match
>> my_plot(x, 'line','-')
Error using [...]
Ambiguous parameter name: line.

InputParser:

正如其他人所提到的,官方推荐的 解析函数输入解析函数输入方法是使用 inputParser类。它支持各种方案,例如指定所需的输入、可选的位置参数和名称/值参数。它还允许对输入执行 确认(例如检查类/类型和参数的大小/形状)

function argtest(varargin)


a = 1;


for ii=1:length(varargin)/2
[~] = evalc([varargin{2*ii-1} '=''' num2str(varargin{2*ii}) '''']);
end;


disp(a);
who

这当然不会检查正确的赋值,但是它很简单,任何无用的变量都会被忽略。它也只适用于数字、字符串和数组,但不适用于矩阵、单元格或结构。

我今天写了这个,然后发现了这些提到。 Mine 使用 struct’s 和 struct‘ overlay’作为选项。它基本上反映了 setstructfields ()的功能,只是不能添加新参数。它还有一个递归选项,而 setstructfields ()会自动执行。 它可以通过调用 struct (args { : })接受成对值的单元格数组。

% Overlay default fields with input fields
% Good for option management
% Arguments
%   $opts - Default options
%   $optsIn - Input options
%       Can be struct(), cell of {name, value, ...}, or empty []
%   $recurseStructs - Applies optOverlay to any existing structs, given new
%   value is a struct too and both are 1x1 structs
% Output
%   $opts - Outputs with optsIn values overlayed
function [opts] = optOverlay(opts, optsIn, recurseStructs)
if nargin < 3
recurseStructs = false;
end
isValid = @(o) isstruct(o) && length(o) == 1;
assert(isValid(opts), 'Existing options cannot be cell array');
assert(isValid(optsIn), 'Input options cannot be cell array');
if ~isempty(optsIn)
if iscell(optsIn)
optsIn = struct(optsIn{:});
end
assert(isstruct(optsIn));
fields = fieldnames(optsIn);
for i = 1:length(fields)
field = fields{i};
assert(isfield(opts, field), 'Field does not exist: %s', field);
newValue = optsIn.(field);
% Apply recursion
if recurseStructs
curValue = opts.(field);
% Both values must be proper option structs
if isValid(curValue) && isValid(newValue)
newValue = optOverlay(curValue, newValue, true);
end
end
opts.(field) = newValue;
end
end
end

我认为使用“默认值”和“新值”这两个变数命名原则可能会更好:

受乔纳斯回答的启发,但更简洁:

function example(varargin)
defaults = struct('A',1, 'B',magic(3));  %define default values


params = struct(varargin{:});
for f = fieldnames(defaults)',
if ~isfield(params, f{1}),
params.(f{1}) = defaults.(f{1});
end
end


%now just access them as params.A, params.B

我根据乔纳斯和里奇・科顿创作了一个功能。它实现了两种功能(灵活的参数或受限制的,这意味着只允许存在于默认值中的变量) ,以及一些其他的东西,如语法糖和健全性检查。

function argStruct = getnargs(varargin, defaults, restrict_flag)
%GETNARGS Converts name/value pairs to a struct (this allows to process named optional arguments).
%
% ARGSTRUCT = GETNARGS(VARARGIN, DEFAULTS, restrict_flag) converts
% name/value pairs to a struct, with defaults.  The function expects an
% even number of arguments in VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name and is case sensitive.)
% Also VARARGIN should be a cell, and defaults should be a struct().
% Optionally: you can set restrict_flag to true if you want that only arguments names specified in defaults be allowed. Also, if restrict_flag = 2, arguments that aren't in the defaults will just be ignored.
% After calling this function, you can access your arguments using: argstruct.your_argument_name
%
% Examples:
%
% No defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} )
%
% With defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} , ...
%               struct('foo', 987, 'bar', magic(3)) )
%
% See also: inputParser
%
% Authors: Jonas, Richie Cotton and LRQ3000
%


% Extract the arguments if it's inside a sub-struct (happens on Octave), because anyway it's impossible that the number of argument be 1 (you need at least a couple, thus two)
if (numel(varargin) == 1)
varargin = varargin{:};
end


% Sanity check: we need a multiple of couples, if we get an odd number of arguments then that's wrong (probably missing a value somewhere)
nArgs = length(varargin);
if rem(nArgs, 2) ~= 0
error('NameValuePairToStruct:NotNameValuePairs', ...
'Inputs were not name/value pairs');
end


% Sanity check: if defaults is not supplied, it's by default an empty struct
if ~exist('defaults', 'var')
defaults = struct;
end
if ~exist('restrict_flag', 'var')
restrict_flag = false;
end


% Syntactic sugar: if defaults is also a cell instead of a struct, we convert it on-the-fly
if iscell(defaults)
defaults = struct(defaults{:});
end


optionNames = fieldnames(defaults); % extract all default arguments names (useful for restrict_flag)


argStruct = defaults; % copy over the defaults: by default, all arguments will have the default value.After we will simply overwrite the defaults with the user specified values.
for i = 1:2:nArgs % iterate over couples of argument/value
varname = varargin{i}; % make case insensitive
% check that the supplied name is a valid variable identifier (it does not check if the variable is allowed/declared in defaults, just that it's a possible variable name!)
if ~isvarname(varname)
error('NameValuePairToStruct:InvalidName', ...
'A variable name was not valid: %s position %i', varname, i);
% if options are restricted, check that the argument's name exists in the supplied defaults, else we throw an error. With this we can allow only a restricted range of arguments by specifying in the defaults.
elseif restrict_flag && ~isempty(defaults) && ~any(strmatch(varname, optionNames))
if restrict_flag ~= 2 % restrict_flag = 2 means that we just ignore this argument, else we show an error
error('%s is not a recognized argument name', varname);
end
% else alright, we replace the default value for this argument with the user supplied one (or we create the variable if it wasn't in the defaults and there's no restrict_flag)
else
argStruct = setfield(argStruct, varname, varargin{i + 1});  %#ok<SFLD>
end
end


end

还有 作为要点提供

对于那些有兴趣拥有真实命名参数(语法类似于 Python,例如: myfunction (a = 1,b = ‘ qwerty’)的人,使用 InputParser (只对 Matlab 而言,Octave 用户至少要等到 v4.2或者你可以尝试一个名为 InputParser2的包装器)。

另外,如果你不想总是输入 argstruct.yourvar而是直接使用 yourvar,你可以使用下面的 片段作者: Jason S:

function varspull(s)
% Import variables in a structures into the local namespace/workspace
% eg: s = struct('foo', 1, 'bar', 'qwerty'); varspull(s); disp(foo); disp(bar);
% Will print: 1 and qwerty
%
%
% Author: Jason S
%
for n = fieldnames(s)'
name = n{1};
value = s.(name);
assignin('caller',name,value);
end
end

我从很久以前就开始使用 process_options.m了。它稳定,易于使用,并且已经包含在各种 Matlab 框架中。虽然对性能一无所知,但可能是因为有更快的实现。

对于 process_options,我最喜欢的特性是 unused_args返回值,它可以用来将输入参数拆分为一组参数,例如子进程。

您可以很容易地定义默认值。

最重要的是: 使用 process_options.m通常会导致 可读可以维持选项定义。

示例代码:

function y = func(x, y, varargin)


[u, v] = process_options(varargin,
'u', 0,
'v', 1);

有一个叫做 parsepvpairs的漂亮的函数可以很好地解决这个问题,只要你能访问 MATLAB 的财务工具箱。它接受三个参数,预期字段名称、默认字段值和实际接收的参数。

例如,这里有一个函数,它在 MATLAB 中创建了一个 HTML 图形,并且可以使用名为“ url”、“ HTML”和“ title”的可选字段值对。

function htmldlg(varargin)
names = {'url','html','title'};
defaults = {[],[],'Padaco Help'};
[url, html,titleStr] = parsepvpairs(names,defaults,varargin{:});


%... code to create figure using the parsed input values
end

MathWorks 已经恢复了这匹老马,但是它提供了非常有用的功能,直接满足了这个需求。它被称为 函数参数验证(一个人们可以并且应该在文档中搜索的短语) ,发布版本 R2019b + 。MathWorks 还为此制作了一个视频。验证的工作原理与人们多年来想出的“技巧”非常相似。这里有一个例子:

function ret = example( inputDir, proj, options )
%EXAMPLE An example.
% Do it like this.
% See THEOTHEREXAMPLE.


arguments
inputDir (1, :) char
proj (1, 1) projector
options.foo char {mustBeMember(options.foo, {'bar' 'baz'})} = 'bar'
options.Angle (1, 1) {double, integer} = 45
options.Plot (1, 1) logical = false
end


% Code always follows 'arguments' block.
ret = [];
switch options.foo
case 'bar'
ret = sind(options.Angle);
case 'baz'
ret = cosd(options.Angle);
end


if options.Plot
plot(proj.x, proj.y)
end


end

这是拆包的东西:

arguments块必须位于任何代码之前(在 help 块之后) ,并且必须遵循函数定义中定义的位置顺序,我相信每个参数都需要提及。必需参数先放,然后是可选参数,接着是名称-值对。MathWorks 还建议不要再使用 varargin关键字,但是 narginnargout仍然有用。

  • 在这种情况下,类需求可以是自定义类,例如 projector
  • 所需的参数可能没有默认值(也就是说,它们是已知的 因为,它们没有默认值)。
  • 可选参数必须有一个默认值(即它们是已知的 因为,它们有一个默认值)。
  • 默认值必须能够传递相同的参数验证。换句话说,zeros(3)的默认值不能作为应该是字符向量的参数的默认值。
  • 名称-值对存储在一个内部转换为 struct 的参数中,这里我称之为 options(暗示我们可以使用 structs 传递关键字参数,如 Python 中的 kwargs)。
  • 非常好,当您在函数调用中按 Tab 键时,名称-值参数将显示为参数提示。(如果您对完成提示感兴趣,我鼓励您也查找 MATLAB 的 functionSignatures.json功能)。

所以在这个例子中,inputDir是一个必需的参数,因为它没有给出默认值。它也必须是一个1xN 的字符向量。如果要反驳这种说法,请注意 MATLAB 将尝试转换提供的参数,以查看转换后的参数是否通过。例如,如果将 97:122作为 inputDir传递,它将传递 inputDir == char(97:122)(即 inputDir == 'abcdefghijklmnopqrstuvwxyz')。相反,由于 zeros(3)不是一个矢量,所以它不能工作。并且忘记在指定字符时使字符串失败,在请求 uint8时使双精度类型失败,等等。那些会被转换。您需要更深入地挖掘以规避这种“灵活性”

接下来,'foo'指定一个名称-值对,其值可能只有 'bar''baz'

MATLAB 有许多 mustBe...验证函数(开始键入 mustBe和点击标签,看看什么是可用的) ,这是很容易的 创建自己的。如果创建自己的,验证函数必须 如果输入不匹配,则给出一个错误,这与 uigetdir不同, 如果用户取消对话框,返回 0 遵循 MATLAB 的约定,调用我的验证函数 mustBe...,所以我有像 mustBeNatural这样的自然函数 数字和 mustBeFile,以确保我传递的文件实际上 存在。

'Angle'指定了一个名称-值对,其值必须是标量双精度数或整数,因此,例如,由于您为 Angle参数传递了一个向量,因此 example(pwd, 'foo', 'baz', 'Angle', [30 70])将无法工作。

你懂的。arguments块有很大的灵活性——我认为太多或太少——但是对于简单的函数,它是快速和简单的。您仍然可能依赖于一个或多个 inputParservalidateattributesassert等来处理更大的验证复杂性,但是我总是尝试首先将内容填充到 arguments块中。如果它变得难看,也许我会做一个 arguments块和一些断言,等等。

如果您正在使用 MATLAB 2019b 或更高版本,处理函数中的名称-值对的最佳方法是使用“ Declare function 实参验证”。

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


% Function code
result = NameValueArgs.Name1 * NameValueArgs.Name2;


end

见: https://www.mathworks.com/help/matlab/ref/arguments.html