我们可以一起使用addOptional和addParameter吗?

时间:2016-10-09 18:22:00

标签: matlab

inputParser提供了addOptional和addParameter。文档(https://www.mathworks.com/help/matlab/ref/inputparser-class.html)说

  

您可以按任意顺序调用addRequiredaddOptionaladdParameter来定义您的方案,但是当您调用使用输入解析器的函数时,您应该传入所需的输入首先,接着是任何可选的位置输入,最后是任何名称 - 值对。

但我不能使这项工作,并得到以下错误。

K>> a = inputParser;
K>> addOptional(a, 'o', 'x');
K>> addParameter(a, 'p', 1);
K>> parse(a, 'w', 'p', 2)

参数'w'是一个字符串,与任何参数名称都不匹配。它无法验证参数'o'

如果我们将默认值定义为数字。

a = inputParser; 
addOptional(a, 'o', 42);
addParameter(a, 'p', 1);
parse(a, 'p', 2);
parse(a, 3, 'p', 2);
parse(a, 3);

它有效。

我错过了什么吗?

2 个答案:

答案 0 :(得分:4)

我不建议将inputParser与允许使用字符数组的可选参数一起使用,因为parse()无法区分用户是否传递参数名称(始终为{{1 }}或可选的输入参数。因此,这种行为的逻辑结果是您无法将char作为可选输入参数传递。

但是,如果为可能为char的可选输入参数指定验证函数,则可以使其正常工作。来自“提示”部分下的addOptional文档:

  

对于可选字符串输入,请指定验证功能。如果没有验证函数,输入解析器会将有效的字符串输入解释为无效的参数名称并引发错误。

这是您的示例生成的错误。

修复您的示例

char是可选的输入参数。如果您知道如何验证'o'需要接受的值,请提供一个验证函数,为这些有效输入返回'o'。例如,如果您知道true将始终是'o'数组,请尝试以下(逐行)。

char

最后一行似乎违反直觉,但事实并非如此!我们希望解析器检测参数a = inputParser; addOptional(a, 'o', 'default', @ischar); addParameter(a, 'p', 1); parse(a, 'x'); % OK parse(a, 'Hello, World!', 'p', 2); % OK parse(a, 'p', 'p', 'p') % OK, although quite cryptic parse(a, 3); % Throws an error, as expected, because 3 is not a char parse(a, 'p', 4) % Throws a somewhat unexpected error, because we meant to set parameter 'p' to value 4 而不是隐式假设它是我们为可选参数'p'提供的字符,我们想省略它。不过,正如我现在要解释的那样,这是预期的行为。

为什么'o'选项会给char带来困难

预期显示的bahviour是因为可选参数和参数参数都不是必需的,即可选的。如果您有两个可选的输入参数inputParser'o1',它们的顺序对输入解析器很重要(这就是为什么MATLAB文档称它们为'可选位置参数)。您永远不能在'o2'的值之前传递'o2'的值。这意味着只有在指定'o1'时才能使用'o2'。换句话说,'o1'阻止使用任何其他可选参数。

对于参数也是如此,这些参数应始终位于其他可选输入参数之后(如您所引用的那样)。因此,如果允许任何可选输入参数为'o1',则它们的行为类似于可选项。结果是MATLAB的char不知道inputParser输入是可选的输入参数还是参数。 MATLAB的开发人员决定要求显式排序可选输入,因此MATLAB可以确定将哪些可选参数传递给char

如果可选输入可能是parse()

,则建议采取的措施

因为使用可选的输入参数需要MATLAB假设某些输入参数引用可选的输入参数,其他引用参数,如果未指定所有可选参数,这可能导致最终用户意外的错误,行为或结果。

如果明确写入以防止这种意外的隐式行为,则输入参数方案会更好。我建议如果需要接受char输入的可选输入参数,则总是使用char创建参数,即名称 - 值对参数。使用接受addParameter输入的可选输入参数仅在不使用任何参数时有效,或者通过显式声明(例如在帮助中),当且仅当给出所有可选输入参数时,才能使用参数输入参数。

答案 1 :(得分:1)

addOptional的验证函数用于确定解析的参数是否与addOptional指定的参数相对应。如果验证函数返回false,则将当前解析的参数传递给下一个addOptional/addParameter

由于性能原因,addOptional的默认验证功能是一个简单的~ischar来区分参数和值。查看TWM员工here的答案。但是,所提供的解决方案并未涵盖所有用例。

以下是适用于任何数据类型以及参数/值结构的解决方案。唯一需要注意的是:您不能使用等于任何参数名称的值。

a = inputParser;

% Validation function needs to check
% - if argument is a parameter name or a value
%   -> any(strcmp(x,a.Parameters))
% - if argument is a parameter/value struct
%   -> isstruct(x) && any(ismember(fieldnames(x),a.Parameters))
addOptional(a,'o','x',@(x)~(any(strcmp(x,a.Parameters)) || isstruct(x) && 
any(ismember(fieldnames(x),a.Parameters))));

addParameter(a, 'p', 1);

%The next three parse commands give all the same result struct

% 'o' as positional parameter
parse(a, 'w', 'p', 2)        

% 'o' as named parameter/value pair
parse(a, 'o', 'w', 'p', 2)   

% parameters provided as param/value struct
pv.o='w';
pv.p=2;
parse(a, pv)

% value of 'o' is a struct
data.x = 1;
parse(a, data)

%You cannot use a value equal to a parameter name
parse(a, 'p', 'p', 2) % FAIL

如果您不介意速度惩罚,我建议您为可选参数编​​写自定义函数

function addOptionalExt(parserObj,key,default)
parserObj.addOptional(key,default,...
    @(x)~(any(strcmp(x,parserObj.Parameters)) || ...
    isstruct(x) && any(ismember(fieldnames(x),parserObj.Parameters))));

然后在你的例子中使用它

a = inputParser;
addOptionalExt(a, 'o', 'x');
addParameter(a, 'p', 1);
parse(a, 'w', 'p', 2)