【问题标题】:When can I pass a literal : to a function?我什么时候可以将文字 : 传递给函数?
【发布时间】:2026-02-17 14:05:01
【问题描述】:

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

>> 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 代码中,我遇到过将切片对象传递给方法的情况。一个用例是一个受this answer启发的函数,其中一个小函数用于绕过Matlabs无法解释magic(5)(3, :),并且可以编写一个辅助函数并用paren(magic(5), 3, :)调用它。

【问题讨论】:

  • 您在寻找 MATLAB 错误吗? writeargs 是一个函数,而不是矩阵。为什么要指定冒号作为参数?
  • @EitanT 每当我的参数将用作切片或索引时。例如,我有一个函数y = p(x, varargin) 定义为y = x(varargin{:});,灵感来自this answer,当我的函数调用确实是Matlab 中缺少magic(5)(3, :) 的一种解决方法时,最好将: 直接传递为在p(magic(5), 3, :).
  • 很有趣,但您应该在问题本身中指定这一点。无论如何,您应该看到this related question 的答案...我相信您正在寻找的答案是您不能将: 传递给函数,但可以传递给对象(类)。或者,您可以传递一个冒号字符 (':'),但这可能不是您想要的。
  • @EitanT 我已经编辑了这个问题。感谢您提供相关问题的指针。
  • @gerrit 我在想: 的某种组合会欺骗matlab 为名为@9​​87654340@ 的变量调用subsref,而不是调用你的函数。

标签: matlab syntax slice


【解决方案1】:

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

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

我对您的用例的建议本质上是this answer(在您的问题的 cmets 中也引用过),但正如您所建议的那样,将索引隐藏在名为 paren 的函数中。此外,它使用默认括号语法而不是调用 subsref,而是使用it's the same anyway。使用字符串冒号!

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.

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • writeargs(:,:) 输出':' ':' 所以它不仅仅是3个或更多变量顺便说一句。我认为我们需要查看subsref 来源才能在这里得出任何有效的结论......
    • 我认为你是对的,如果你看一下 subsref 的 cmets,括号内的参数似乎被传递到 subsref 函数中,冒号总是作为字符串传递......大概是默认的 subsref 实现句柄这和 writeargs 示例仅显示 subsref 的结果