11

在什么情况下可以将文字传递:给 Matlab 函数?我通过实验发现,有时,文字:作为 string 传递':',但在其他情况下,会引发错误。例如:

>> type writeargs

function writeargs(varargin)

disp(varargin);

end

>> writeargs(:)
Undefined variable writeargs.

>> writeargs(:, 1)
Undefined variable writeargs.

>> writeargs(:, 1, :)
    ':'    [1]    ':'

>> writeargs(:, :, :)
    ':'    ':'    ':'

>> writeargs(1, 2, :, 4, 5)
    [1]    [2]    ':'    [4]    [5]

>> writeargs(1, 2, :, end)
Error using writeargs
Too many output arguments.

我的印象是,如果至少传递了三个参数,则允许使用此语法。这似乎是任意的。这里的法律语法是什么?

编辑:评论要求用例。一个用例可能是每当我的参数将用作切片或索引时。在 Python 代码中,我遇到过将切片对象传递给方法的情况。一个用例是受此答案启发的函数,其中使用一个小函数来规避 Matlabs 无法解释的问题magic(5)(3, :),并且可以编写一个辅助函数并使用paren(magic(5), 3, :).

4

2 回答 2

2

您不应该将文字 : 传递给函数。用于索引的冒号仅适用于直接变量(参见此处此处)。冒号不是真正的对象,也没有类型。如果您应该将它用作函数参数,它需要是一个类型化的对象。当然,函数调用和变量索引具有相同的语法可能会令人困惑。但是,如果您要求使用冒号作为函数参数的合法语法,则没有。

话虽如此,但正如您所观察到的,它在某些情况下仍然有效。这是由于 MATLAB 采取了一些预处理步骤,只有 MathWorks 可以处理。当您给它三个或更多参数(或两个参数,都是冒号)时,MATLAB 几乎似乎通过类似 subsref 的预处理来调用该函数,但当您给它的参数少于这个时,它不会。去搞清楚。MathWorks 将避免对此给出任何决定性的解释。我怀疑,MATLAB 在应用 subsref 后在内部使用字符串化冒号,因为这是您在函数中收到文字冒号时看到的内容,并且索引操作似乎始终如此。例如尝试>> m(3, ':');

我对您的用例的建议本质上是这个答案(也在您问题的评论中引用),但正如您所建议的那样,将索引隐藏在名为 paren 的函数中。此外,它使用默认括号语法而不是调用 subsref,但无论如何都是一样的。使用字符串化的冒号!

function result = paren(variable, varargin)

    result = variable(varargin{:});

然后调用类似的东西:

>> paren(magic(5), 3, ':');

总之,您不应该指望在 MATLAB 中使用文字 : 作为函数参数,即使它可能适用于特殊情况。使用字符串冒号':'。

边注

您可以使用 subsref 来调用函数:

>> subsref(@magic, substruct('()', {3}))

通过这种方式,您可以链接函数调用和引用:

>> subsref(subsref(@magic, substruct('()', {3})), substruct('()', {':'}))

但这实际上与使用临时变量相同。首先评估内部 subsref,并将其结果作为输入参数传递给外部 subsref 调用。

即使使用 subsref 的链接机制,您也不能强制 MATLAB 接受两个连续的括号对,例如 magic(3)(:)。

>> magic(3)(:)
??? Error: ()-indexing must appear last in an index expression.

>> subs(1) = substruct('()', {3});
>> subs(2) = substruct('()', {':'});
>> subsref(str2func('magic'), subs)
??? Error using ==> subsref
Only a dot field name can follow ()'s.
于 2013-05-24T10:23:53.757 回答
1

writeargs(:) 和 writeargs(:,1) 将 writeargs 视为局部范围的变量,并尝试使用冒号运算符来索引“不存在”的变量。

使用三个以上的参数调用该函数......对不起,我不明白为什么会存在这种行为,但我怀疑它是用一个或两个参数隐式调用 subsref,而不是三个或更多参数。

您可以通过在函数中的 disp 调用上放置断点来测试它,您会看到它仅在给出三个以上参数时才会被命中

于 2013-03-29T14:43:21.197 回答