【问题标题】:Can we use addOptional and addParameter together?我们可以同时使用 addOptional 和 addParameter 吗?
【发布时间】:2017-04-21 20:41:23
【问题描述】:

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);

它有效。

我错过了什么吗?

【问题讨论】:

    标签: matlab


    【解决方案1】:

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

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

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

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

    修正你的例子

    '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 选项给inputParser 带来困难

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

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

    如果可选输入可能是char,建议采取的措施

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

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

    【讨论】:

      【解决方案2】:

      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)
      

      【讨论】:

        猜你喜欢
        • 2017-11-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多