交叉参数函数参数验证是否不适用于(重复)参数?

Does cross-argument function argument validation not work with (Repeating) arguments?

总结

使用依赖于多个的function argument validation(Repeating) 参数块中的参数,传递当前参数 通常传递给验证函数,而其他参数作为 部分人口 元胞阵列。这与非 (Repeating) 参数块中的工作方式相比较。这是预期的行为还是错误?

场景

考虑下面的函数 dummy1,它使用自定义 参数验证 函数 mustBeEqualSize 以确保参数 xy 具有相同的大小。 由于 y 的验证取决于 x 的值,我称之为 “交叉参数”验证*.

*如果有更好的说法, 请评论或编辑。

function dummy1(x, y)
    arguments
       x (1,:) 
       y (1,:) {mustBeEqualSize(x,y)}
    end
    % Do something with x and y.
end

function mustBeEqualSize(a, b)
    % Validates that function arguments have the same size.
    if ~isequal(size(a), size(b))
        eid = 'Size:notEqual';
        msg = "Arguments must have the same size.";
        throwAsCaller(MException(eid, msg))
    end
end

正如所写,这种形式的参数验证按预期工作:

dummy1(1:3, 4:6)  % arguments have same size; validation passes (okay)
dummy1(1:3, 4:7)  % arguments have different size; validation fails (okay)

在这两种情况下,在参数期间调用 mustBeEqualSizey 的验证,ab 都作为 1xN 双数组接收, 这符合我的期望:

% Inside call to mustBeEqualSize(x,y), when x=1:3, y=4:6 in dummy1
a =
     1     2     3
b =
     4     5     6

修改dummy1接受重复出现问题 通过将 (Repeating) 添加到参数块来获取参数:

function dummy2(x, y)
    arguments (Repeating)
       x (1,:) 
       y (1,:) {mustBeEqualSize(x,y)}
    end
    % Do something with each pair of x-y arguments.
    % In this body, both x and y will be 1xN cell arrays, where N is the
    % number of argument groups passed.
end

现在当我们调用 dummy2(1:3, 4:6) 时,参数验证失败。使用 调试器,我发现当 mustBeEqualSizeya 的验证作为 1x1 元胞数组接收,而 b 仍然是 1x3 双精度数组:

% Inside call to mustBeEqualSize(x,y), when x=1:3, y=4:6 in dummy2
a =
  1×1 cell array
    {[1 2 3]} 
b =
     4     5     6

当使用更多重复参数时,问题更加明显:

dummy2(1:3, 4:6, 1:3, 4:6, 1:3, 4:6)  % 3 argument groups

结果

a =
  1×3 cell array
    {[1 2 3]}    {0×0 double}    {0×0 double}
b =
     4     5     6

似乎在 dummy2y 的验证期间,y 取值 当前参数正在验证,而 x 是一个(部分填充) MATLAB 分配用于保存所有 x 参数的元胞数组缓冲区 已通过。

这当然打破了交叉参数验证,因为只有 当前正在验证的论点实际上将自己呈现为一个 参数,而其他参数将它们呈现为元胞数组 缓冲区。

问题

(Repeating) 的交叉参数验证与非 (Repeating) 参数的不匹配是一个错误,还是 MATLAB 不支持 (Repeating) 参数的交叉参数验证?如果预期存在这种行为差异,是否有任何方法可以使用 (Repeating) 个参数进行交叉参数验证?

MATLAB 文档说明了以下关于参数验证的内容 重复参数

In the function, each repeating argument becomes a cell array with the number of elements equal to the number of repeats passed in the function call. The validation is applied to each element of the cell array.

这似乎没有说明如何 交叉论证 验证 应该使用重复参数。

使用 MATLAB R2021a (9.10.0.1602886) 测试。

注意:这是我们没有考虑的设计的边缘情况。我已经让相关的开发团队知道了,他们会考虑在未来的版本中修复它。

短期内,您可以尝试获取元胞数组的最后一个非 0x0 double 元素:

function mustBeEqualSize(x,y)
    if iscell(x)
        % Get last non-empty element of `x`
        notEmptyDouble = @(e)isa(e,'double') && ~isequal(size(e), [0, 0]);
        idx = find(cellfun(notEmptyDouble, x), 1, 'last');
        x = x{idx};
    end

    % check equality
    if ~isequal(size(x), size(y))
        error("size mismatch")
    end
end

这将适用于所有 non-empty 数组,但不幸的是,由于使用的是空类型,因此不适用于 dummy2([],[])

此外,我想指出,无论验证器最终为这个用例工作,请考虑它是否会破坏函数 if/when 此问题已解决。 IE。如果此函数需要同时处理双精度数组和元胞数组,将来可能会出现问题。但是,如果此函数只需要双数组,则可以使用

对其进行约束
arguments(Repeating)
    a (1,:) double
    b (1,:) double {mustBeEqualSize(x,y)}
end

这与验证器中的iscell检查相结合,应该future-proof这个功能。