5

我有一个 MATLAB 文件,其中包含一个名为sandbox. 该函数又包含两个嵌套函数mysummyprod,它们在功能和允许的参数上是相同的,除了一个@sum在内部使用而另一个在@prod内部使用。我的目标是创建一个在两者中都使用的包装函数,mysummyprod负责所有的验证和输入解析。这个函数被称为applyFunc

这就是棘手的地方。mysummyprod两种形式:

  1. mysum(v)返回sum(v, 1)
  2. mysum(v, 'imag')返回sum(v, 1) + 1i

任何其他输入组合都应引发错误。

我无法inputParser解析这些不同的输入组合,特别是可选的字符串输入。这是代码:

function sandbox()
%% Data
v = [1 4; 3 3];

%% Calculations
s = mysum(v);
si = mysum(v, 'imag');
p = myprod(v);
pi = myprod(v, 'imag');

%% Accuracy tests
assert(isequal(s, [4 7]))
assert(isequal(si, [4+1i 7+1i]))
assert(isequal(p, [3 12]))
assert(isequal(pi, [3+1i 12+1i]))

    function x = mysum(varargin)
        x = applyFunc(@sum, varargin{:});
    end

    function x = myprod(varargin)
        x = applyFunc(@prod, varargin{:});
    end
end

function x = applyFunc(func, varargin)

p = inputParser();
p.addRequired('func', @(x) validateattributes(x, {'function_handle'}, {'scalar'}));
p.addRequired('v', @(x) validateattributes(x, {'double'}, {}, 'applyFunc:msg', 'v'));
p.addOptional('imag', '', @(x) validatestring(x, {'imag', ''})); % THIS LINE IS THE PROBLEM
p.parse(func, varargin{:});

f = p.Results.func;
v = p.Results.v;
strflag = p.Results.imag;

x = f(v);
if ~isempty(strflag)
    validatestring(strflag, {'imag'});
    x = x + 1i;
end
end

导致问题的行是这一行(如上面的代码中标记的那样):

p.addOptional('imag', '', @(x) validatestring(x, {'imag', ''}));

inputParser 的文档说:

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

不幸的是,我不知道如何做到这一点。我缺少什么简单的东西还是什么?如果'imag'根本没有传递参数(如sand的赋值p),代码可以正常工作,但如果我传递它,我会收到此错误:

Error using sandbox>applyFunc (line 32)
The value of 'imag' is invalid. It must satisfy the function:
@(x)validatestring(x,{'imag',''}).
Error in sandbox/mysum (line 18)
        x = applyFunc(@sum, varargin{:});
Error in sandbox (line 7)
si = mysum(v, 'imag'); 

有什么帮助吗?

4

2 回答 2

5

问题是validatestring从单元格参数 ( ) 返回匹配的字符串,{'imag',''}而不是指示它是否通过验证的布尔值。相反,使用strcmpand any

@(x) any(strcmp(x,{'imag', ''}))

此外,validatestring如果输入字符串不匹配'imag'''(实际上只是'imag'因为空字符串仅在 R2014a+ 中匹配),它会抛出错误而不是返回 false,以便inputParser可以返回适当的错误。

解决此问题的另一个好方法是完全更改 的语法,applyFunc以便使用 Parameter-Value 作为参数和经过验证的布尔值作为输入,而不是仅仅作为可选'imag'字符串输入参数。'imag'

Amro 在评论中建议的输入定义:

p.addParameter('imag', false, @(x)validateattributes(x, {'logical'}, {'scalar'}))

用法:

mysum(x,'imag',true)
mysum(x)               % default is equivalent to mysum(x,'imag',false)

p.Result.imag这将通过成为标量来简化其余代码logical。我会建议:

x = f(v) + p.Result.imag*1i;
于 2013-12-17T23:19:12.997 回答
2

问题不在于inputParser,我认为问题在于validatestring

1)首先它与空字符串不匹配:

>> x = ''
x =
     ''

>> validatestring(x, {'imag',''})
Expected input to match one of these strings:

imag,

The input did not match any of the valid strings.
Caused by:
    Error using validatestring>checkString (line 85)
    Expected input to be a row vector. 

2) 其次,如果匹配成功,则返回已解析的字符串(来自有效选择之一),而不是 true/false。inputParser要求验证函数要么返回一个布尔值,要么在失败时只返回一个错误。

于 2013-12-17T23:21:03.187 回答