71

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

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 是否有任何辅助函数可以提供帮助?

4

15 回答 15

66

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

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
于 2010-05-05T19:40:45.583 回答
45

InputParser对此有所帮助。有关详细信息,请参阅解析函数输入

于 2010-05-05T17:47:24.487 回答
13

我可以为此烦恼几个小时,但仍然没有对一般 Matlab 签名处理有一个很好的格式塔视图。但这里有几条建议。

首先,采用自由放任的方法来验证输入类型。相信来电者。如果你真的想要强类型测试,你需要像 Java 这样的静态语言。尝试在 Matlab 中的每一个地方强制执行类型安全,你最终将有很大一部分 LOC 和执行时间专门用于运行时类型测试和用户空间中的强制,这以 Matlab 的大量功能和开发速度为代价. 我经过惨痛的教训才学到这个。

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

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

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

这是解析调用的样子。

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

这是一个以这种方式实现名称/值解析的函数。您可以将其挖空并用 inputParser、您自己的类型约定等替换它。我认为 n-by-2 单元格约定使源代码可读性好;考虑保留它。在接收代码中处理结构通常更方便,但使用表达式和文字构造 n×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 中的一流类型。

于 2010-05-05T21:44:19.677 回答
13

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块必须在任何代码之前(在帮助块之后确定)并且必须遵循函数定义中定义的位置顺序,我相信每个参数都需要提及。首先是必需的参数,然后是可选参数,然后是名称-值对。MathWorks 还建议不再使用varargin关键字,但nargin仍然nargout有用。

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

所以在这个例子中,inputDir是一个必需的参数,因为它没有给出默认值。它还必须是 1xN 字符向量。好像与该声明相矛盾,请注意 MATLAB 将尝试转换提供的参数以查看转换后的参数是否通过。例如,如果您传递97:122as inputDir,它将传递 and inputDir == char(97:122)(ie inputDir == 'abcdefghijklmnopqrstuvwxyz')。相反,zeros(3)由于它不是向量,因此不起作用。并且忘记在指定字符时使字符串失败,在需要 uint8 时使双精度数失败等。这些将被转换。您需要深入挖掘以规避这种“灵活性”。

继续,'foo'指定一个名称-值对,其值可能仅为'bar''baz'

MATLAB 有许多mustBe...验证功能(开始输入 mustBe并点击选项卡以查看可用的功能),并且很容易创建您自己的功能。如果您创建自己的,如果输入不匹配,验证函数必须给出错误,不像,说,如果用户取消对话框uigetdir,则返回。0就个人而言,我遵循 MATLAB 的约定并调用我的验证函数 mustBe...,所以我有类似mustBeNatural自然数的函数,并mustBeFile确保我传递了一个实际存在的文件。

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

你明白了。块有很大的灵活性arguments——太多也太少,我认为——但对于简单的功能,它又快又容易。你仍然可能依赖一个或多个inputParser, validateattributes, assert, 等等来解决更大的验证复杂性,但我总是arguments首先尝试把东西塞进一个块中。如果它变得难看,也许我会做一个arguments块和一些断言等。

于 2020-02-11T22:58:11.110 回答
6

我个人使用从许多 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

与任何未记录的函数一样,没有任何保证,并且可以在后续版本中将其从 MATLAB 中删除,恕不另行通知...无论如何,我相信有人在 File Exchange 上发布了它的旧版本作为getargs ..

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

$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类。它支持各种方案,例如指定所需的输入、可选的位置参数和名称/值参数。它还允许对输入执行验证(例如检查参数的类/类型和大小/形状)

于 2010-05-06T12:53:06.893 回答
5

阅读Loren关于这个问题的内容丰富的帖子。不要忘记阅读评论部分...... - 你会看到这个主题有很多不同的方法。它们都有效,因此选择首选方法实际上是个人品味和可维护性的问题。

于 2010-05-05T20:09:29.940 回答
3

我更喜欢这样的本土样板代码:

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 函数获取参数的方式相同。

希望有帮助,

将要

于 2010-05-05T19:19:23.650 回答
1

这是我正在尝试的解决方案,基于 Jonas 的想法。

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
于 2010-05-06T09:40:08.513 回答
1

多年来我一直在使用process_options.m. 它稳定,易于使用,并已包含在各种 matlab 框架中。虽然对性能一无所知——可能是有更快的实现。

我最喜欢的功能process_optionsunused_args返回值,它可用于将输入参数拆分为参数组,例如子进程。

您可以轻松定义默认值。

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

示例代码:

function y = func(x, y, varargin)

    [u, v] = process_options(varargin,
                             'u', 0,
                             'v', 1);
于 2014-09-23T08:08:38.520 回答
1

受乔纳斯回答的启发,但更紧凑:

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
于 2014-01-13T18:48:19.387 回答
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
于 2016-12-07T18:10:32.110 回答
1

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

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

于 2021-08-12T10:56:26.387 回答
0

I ended up writing this today, and then found these mentions. Mine uses struct's and struct 'overlays' for options. It essentially mirrors the functionality of setstructfields() except that new parameters can not be added. It also has an option for recursing, whereas setstructfields() does it automatically. It can take in a cell array of paired values by calling 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

I'd say that using the naming convention 'defaults' and 'new' would probably be better :P

于 2011-09-11T06:05:13.670 回答
0

我制作了一个基于 Jonas 和 Richie Cotton 的函数。它实现了两个功能(灵活的参数或受限的,这意味着只允许存在于默认值中的变量),以及一些其他的东西,比如语法糖和健全性检查。

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

可用作 Gist

对于那些对真正的命名参数感兴趣的人(使用类似于 Python 的语法,例如:myfunction(a=1, b='qwerty'),请使用 InputParser(仅适用于 Matlab,Octave 用户必须等到 v4.2至少,或者您可以尝试一个名为InputParser2的包装器)。

另外作为奖励,如果您不想总是输入argstruct.yourvar而是直接使用,您可以使用Jason Syourvar的以下代码段:

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
于 2014-06-10T10:05:48.960 回答
0
function argtest(varargin)

a = 1;

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

disp(a);
who

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

于 2010-08-11T13:17:20.013 回答