元组使用点表示法的原因

  • 本文关键字:表示 元组 rust
  • 更新时间 :
  • 英文 :


是否有任何技术原因Rust被设计为使用点符号而不是使用索引符号(t[2])元组?

let t = (20u32, true, 'b')
t.2 // -> 'b'

点符号在访问结构体和对象的属性时似乎很自然。我在网上找不到资源或解释

我没有参与设计决策,但这是我的观点:

元组包含混合类型。也就是说,不能保证属性type_of(t[i]) == type_of(t[j])

然而,传统索引工作的前提是t[i]中的i不需要是编译时常数,这反过来意味着t[i]类型需要对所有可能的i保持一致。在所有其他实现索引的rust集合中都是如此。具体来说,通过实现Index trait, rust类型可以被索引,定义如下:

pub trait Index<Idx> where Idx: ?Sized {
    type Output: ?Sized;
    fn index(&'a self, index: Idx) -> &'a Self::Output;
}

所以如果你想要一个元组来实现索引,Self::Output应该是什么类型?实现这一点的唯一方法是使Self::Output成为一个enum,这意味着在程序员方面,元素访问将不得不封装在一个无用的match t[i]子句(或类似的东西)中,并且您将在运行时而不是编译时捕获类型错误。

此外,您现在必须实现边界检查,这也是一个运行时错误,除非您在元组实现中很聪明。

您可以通过编译时常量来要求索引来绕过这些问题,但是此时元组项访问假装表现得像一个正常的索引操作,而实际上与所有其他rust容器的行为不一致,这没有什么好处。

这个决定是在RFC 184中做出的。Motivation部分有详细信息:

现在访问元组和元组结构的字段是非常痛苦的——必须单独依靠模式匹配来提取值。这成为了一个问题,因此在标准库(core::tuple::Tuple*)中创建了12个特征,以使元组值访问更容易,并添加了.valN().refN().mutN()方法来帮助解决这个问题。但这并不是一个很好的解决方案——它要求在标准库中实现这些特征,而不是在语言中实现,并且需要在使用时导入这些特征。总的来说,这不是一个问题,因为大多数时候std::prelude::*是导入的,但这仍然是一个hack,并不是真正解决手头问题的方法。它还只支持长度不超过12的元组,这通常不是问题,但强调了当前情况有多糟糕。

使用t.2语法而不是t[2]语法的原因在下面的注释中得到了最好的解释:

索引语法其他地方具有一致的类型,但是元组是异构的,因此a[0]a[1]将具有不同的类型。

我想从我使用函数式语言(Ocaml)的经验中提供一个答案,因为我已经发布了这个问题。

除了@rom1v引用之外,像a[0]这样的索引语法在其他地方也用于某种序列结构,而元组则不是。例如,在Ocaml中,元组(1, "one")被认为具有类型int * string,这符合数学中的笛卡尔积(即平面为R^2 = R * R),另外,通过nth索引访问元组被认为是惟一的。

由于其多态性质,元组几乎可以被认为是一个记录/对象,通常更喜欢像a.fieldName这样的点表示法作为访问其字段的约定(除了像Javascript这样的语言,它将对象视为字典,并允许像a["fieldname"]这样的字符串字面量访问)。我所知道的唯一使用索引语法来访问字段的语言是Lua。

就我个人而言,我认为像a.(0)这样的语法往往比a.0看起来更好,但这可能是有意(或无意)尴尬的,考虑到在大多数函数式语言中,理想的模式匹配元组而不是通过索引访问它。由于Rust也是命令式的,所以像a.10这样的语法可以很好地提醒您模式匹配或"使用结构体"。

最新更新