为什么在Matlab中,单元数组中的尾随逗号是有效的语法?

18

今天我惊讶地发现

A = {1,2,3}

B = {1,2,3,}

在MATLAB中,{ }[ ] 都是有效的语法。我本来以为第二个语句会导致错误。但据我所知,它们产生了完全相同的单元数组(all([A{:}] == [B {:}]) 返回 true)。

第二种语法之所以被允许,是否有什么原因?这是解析器中的一个错误吗?AB 是否确实相同?

有趣的是,以下语法被允许:

C = {1,2,3,,,}

8
有趣。{1,2,4,;;;;4,5,6;;;}也是被允许的。 - Luis Mendo
1
@LuisMendo 让我感到奇怪的是,它最终成为了一个漂亮而紧凑的矩形。看起来里面至少应该有一些空行或其他东西... - chessofnerd
5
B={1,2,3,} 是滥用,但 {1,2,4,;;;;4,5,6;;;} 就是十足的邪恶。 - brodoll
2
但至少Matlab会让你知道它是不必要的 ;) - Robert Seifert
4
@thewaywewalk,我讨厌的是它警告我相比于str2double,使用str2num速度较慢之类的内容。如果我想要用str2double,我会明确地使用它,你个糟糕的IDE!!!请帮我翻译成中文。 - chessofnerd
显示剩余9条评论
3个回答

21

这只是猜测,不是答案。

我们可以查看符号参考并发现逗号,可以被用作

命令或语句分隔符

要在同一行中输入多个MATLAB命令或语句, 请使用逗号分隔每个命令或语句:

for k = 1:10, sum(A(k)), end

在这一行中:

B = {1,2,3,}
因此,在3之后需要一个语句,但实际上只有},这意味着是cell array的结尾,是一个有效的语句。

分号;有三种官方用途:

数组行分隔符

当在方括号内用于创建新数组或连接现有数组时,分号可创建数组中的一个新行:

A = [5, 8; 3, 4]

输出抑制符

当置于命令末尾时,分号告诉MATLAB不要显示该命令的任何输出。在此示例中,MATLAB不会显示生成的100x100矩阵:

A = ones(100, 100);

命令或语句分隔符

与逗号运算符一样,您可以通过使用分号将多个MATLAB命令输入到一行中。对于以分号终止的命令,MATLAB会抑制输出,而对于以逗号终止的命令,则显示输出。

在此示例中,变量A和C的赋值以分号终止,因此不会显示。由于对B的赋值是以逗号终止的,因此显示这个命令的输出:

A = 12.5; B = 42.7, C = 1.25;

因此,在这一行中:

x = {1,2,3,;5,6,7}

3, 后面遵循有效语句 Array Row Separator。接下来期望一个新的语句, 在这个例子中是双重 5。有效。


现在考虑以下情况:

x = {1,2,3,;;;;4,5,6;;;}

如上所述,在3,之后是语句Array Row Separator,紧接着的语句可能是从一些底层以C编写的程序核心中借用的null statement - NOP,它基本上意味着:什么也不做。因此,在3,;之后,跟着三次"什么也不做",然后才来下一个语句。毫无意义,因为Matlab告诉你:多余的分号是不必要的但是是有效的

它还允许你进行无意义的操作,例如:

if true
    ;
end

这也很可能是为什么的原因

C = {1,2,3,,,} 

因为逗号,不是一个空语句,所以返回了一个错误,但在第一个逗号之后需要一个语句。


总的来说:看起来很奇怪,但实际上对我来说似乎很合乎逻辑,因为Matlab在内部使用了大量C代码,并考虑了空语句,所以提到的所有内容都是有效的语法。


其他语言呢?

在Python中,像x = [1,2,3,;;;;4,5,6;;;]这样使用分号是无效的,即使在预期的Matlab克隆版本numpy中也是如此,除非使用这种不常见的语法a = np.matrix('1,2,3;4,5,6')进行包装。

a = np.matrix('1,2,3,;;;;4,5,6;;;')

如果加上分号;,也会报错,因为在任何情况下分号都被解释为数组行分隔符,这会使编译器抱怨行大小不一致。

然而,

x = [1,2,3,]

PythonIronPython 中,VBScriptLua 中也是有效的语法,正如mlepage的回答中提到的那样。这些语言有什么共同之处?它们都是(或多或少)在运行时解释的脚本语言。这不仅仅适用于Matlab。因此,OP的兴奋是没有根据的。


那真的很有道理。感谢解释。+1。 - rayryeng
6
我很想把这个问题投向The MathWorks,看看他们是否会回答! - sco1
我认为这不是正确的逻辑。我在我的答案底部解释了原因。 - Cris Luengo

5
许多语言允许在列表中添加一个额外的元素分隔符,如前所述。但这与运行时解析无关,即使在C语言中也是如此。这与使用便捷性有关,这是一项旨在帮助用户的功能。例如,在C语言中,您可以定义一个枚举如下:
enum E {
   a,
   b,
   c,
};

c后面加逗号是可选的,但是被允许。这样做可以更容易地添加和删除此类列表中的元素,并且可以更轻松地通过编程生成此类列表(mlepage's answer是正确的!)。
因此,在大多数(如果不是所有)编程语言中允许在末尾添加一个额外的逗号,这对于MATLAB来说也是有意义的。列表开头的额外逗号则不太合理,但我猜他们之所以支持它,是因为这并不会有什么影响。
连续多个逗号是没有意义的,这将意味着存在未指定的其他元素。
但是,多个分号是怎么回事呢?正如Luis Mendo mentioned所提到的,[1;;2]是合法的语法。这与其他语言的做法相比确实有很大的偏差。
然而,这与MATLAB使用换行符的方式是一致的。在MATLAB中,换行符是有意义的。当使用[]定义数组时,换行符表示新的数据行:
M = [ 1, 2, 3,
      4, 5, 6,
      7, 8, 9,
    ];

是相同的

M = [1,2,3; 4,5,6; 7,8,9];

(注意,在某些情况下,允许在每行末尾使用逗号可能会很方便。)
(还要注意,我在这里使用 [] 来连接,完全相同的逻辑也适用于 {}。)
但是由于MATLAB希望尽可能地允许,只要保持不含糊,以上代码与以下代码相同:
M = [ 1, 2, 3,
      4, 5, 6,


      7, 8, 9,
    ];

如果允许出现空行没有问题,为什么不允许呢?
由于每个换行符对应一个分号,因此上述代码与以下代码相同:
M = [ 1, 2, 3,;...
      4, 5, 6,;...
              ;...
              ;...
      7, 8, 9,;...
    ];

与...相同

M = [ 1, 2, 3,; 4, 5, 6,; ; ; 7, 8, 9,; ];

因此,MATLAB必须能够解析它,无论它是否有意义。


thewaywewalk的回答的反驳:

论点是,,;都被定义为语句分隔符,但不知何故认为;;;是有效的语句,而,,,则不是。这是不正确的:

disp(0),,,disp(1)
disp(0);;;disp(1)

这两种写法都是MATLAB语法的有效写法(R2017a可以解析这两种写法而无错误)。

此外,答案混淆了表达式语句disp(0)是一条语句。该语句中的0是一个表达式。在M=[1,2,3]中,逗号分隔的内容是表达式,而不是语句分隔符。

事实上,在MATLAB中,逗号和分号具有多重含义,具体取决于上下文。语句末尾的逗号和分号(包括空语句)与连接表达式中的逗号和分号([1,2;3,4])不同。逗号还可以分隔函数调用括号内的表达式,其中分号不被允许。

只为明确这一点:

1,,,4

是有效的,而

[1,,,4]

不是这样的。这两个语句中逗号的功能是不同的。

简而言之,那个答案中使用的逻辑是错误的。


我从未说过在数组之外使用1,,,4是无效的,因此我不明白为什么我的逻辑在OP的情况下是错误的,因为它显然不是.. 至于其他方面,我已经明确表示,我只是猜测,因此欢迎任何深入的纠正 ;) - Robert Seifert
@thewaywewalk:我猜我将“逗号,不是空语句,但在第一个逗号之后需要一个语句”解释为那样。如果我误解了您的文本,对不起 :)。 - Cris Luengo

2

如果代码将从其他代码生成,允许语言中存在尾随标点符号会很方便。

例如,Lua允许尾随逗号,因此生成Lua代码非常容易。

您不必在生成代码中特殊处理省略最后一个逗号的情况,只需为每个项目打印ITEM-THEN-COMMA即可。


@Wolfie:为什么不呢?这对我来说似乎是正确的推理。请注意,大多数(全部?)编程语言都允许这样做,不仅可用于以程序方式生成代码,而且可以使在源代码中编辑数据变得容易。 - Cris Luengo
@Cris 我甚至想不起来曾经读过这个问题,评论已删除,看起来是一个合理的答案!可能是个糟糕的日子... - Wolfie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接