为什么 Scala 的元组语法如此不同寻常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6884298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is Scala's syntax for tuples so unusual?
提问by yura
In mathematics and computer science, a tuple is an ordered list of elements. In set theory, an (ordered) n-tuple is a sequence (or ordered list) of n elements, where n is a positive integer.
在数学和计算机科学中,元组是元素的有序列表。在集合论中,(有序)n 元组是 n 个元素的序列(或有序列表),其中 n 是正整数。
So, for example, in Python the 2nd item of a tuple would be accessed via t[1].
因此,例如,在 Python 中,元组的第二项将通过t[1].
In Scala, access is only possible via strange names t._2.
在 Scala 中,只能通过陌生名称进行访问t._2。
So the question is, why can't I access data in tuples as Sequence or List if it is by definition? Is there some sort of idea or just yet not inspected?
所以问题是,如果按照定义,为什么我不能以 Sequence 或 List 的形式访问元组中的数据?是否有某种想法或尚未检查?
回答by Jean-Philippe Pellet
Scala knows the arity of the tuples and is thus able to provide accessors like _1, _2, etc., and produce a compile-time error if you select _3on a pair, for instance. Moreover, the type of those fields is exactly what the type used as parameter for Tuple(e.g. _3on a Tuple3[Int, Double, Float]will return a Float).
Scala 知道元组的数量,因此能够提供像_1、_2等的访问器,例如,如果您选择_3一对,则会产生编译时错误。此外,这些字段的类型正是用作参数的类型Tuple(例如_3aTuple3[Int, Double, Float]将返回 a Float)。
If you want to access the nth element, you can write tuple.productElement(n), but the return type of this can only be Any, so you lose the type information.
如果要访问第n个元素,可以写tuple.productElement(n),但是this的返回类型只能是Any,这样就丢失了类型信息。
回答by Vlad Gudim
I believe the following excerpt from "Programming in Scala: A Comprehensive Step-by-Step Guide" (Martin Odersky, Lex Spoon and Bill Venners) directly addresses both of your questions:
我相信以下摘自“Scala 编程:综合分步指南”(Martin Odersky、Lex Spoon 和 Bill Venners)直接解决了您的两个问题:
Accessing the elements of a tuple
You may be wondering why you can't access the elements of a tuple like the elements of a list, for example, with "pair(0)". The reason is that a list's apply method always returns the same type, but each element of a tuple may be a different type: _1 can have one result type, _2 another, and so on. These _N numbers are one-based, instead of zero-based, because starting with 1 is a tradition set by other languages with statically typed tuples, such as Haskell and ML.
访问元组的元素
您可能想知道为什么不能像列表的元素一样访问元组的元素,例如,使用“pair(0)”。原因是列表的 apply 方法总是返回相同的类型,但元组的每个元素可能是不同的类型:_1 可以有一种结果类型,_2 可以有另一种,依此类推。这些 _N 数字是从 1 开始的,而不是从 0 开始,因为从 1 开始是其他具有静态类型元组的语言(例如 Haskell 和 ML)设置的传统。
Scala tuples get very little preferential treatment as far as the language syntax is concerned, apart from expressions '(' a1, ..., an ')'being treated by the compiler as an alias for scala.Tuplen(a1, ..., an) class instantiation. Otherwise tuples do behave as any other Scala objects, in fact they are written in Scala as case classes that range from Tuple2 to Tuple22. Tuple2 and Tuple3 are also known under the aliases of Pair and Triple respectively:
除了'(' a1, ..., an ')'编译器将表达式视为 scala.Tuplen( a1, ..., an) 类实例化的别名之外,Scala 元组在语言语法方面几乎没有得到什么优惠待遇。否则元组的行为与任何其他 Scala 对象一样,实际上它们是在 Scala 中编写为case 类的,范围从 Tuple2 到 Tuple22。Tuple2 和 Tuple3 也分别以 Pair 和 Triple 的别名为人所知:
val a = Pair (1,"two") // same as Tuple2 (1,"two") or (1,"two")
val b = Triple (1,"two",3.0) // same as Tuple3 (1,"two",3.0) or (1,"two",3.0)
回答by tenshi
One big difference between List, Seqor any collection and tuple is that in tuple each element has it's own type where in List all elements have the same type.
之间的一个很大的区别List,Seq任何收集和元组或者是在元组的每个元素都有它自己的类型,其中在列表中的所有元素都具有相同的类型。
And as consequence, in Scala you will find classes like Tuple2[T1, T2]or Tuple3[T1, T2, T3], so for each element you also have type parameter. Collections accept only 1 type parameter: List[T]. Syntax like ("Test", 123, new Date)is just syntactic sugar for Tuple3[String, Int, Date]. And _1, _2, etc. are just fields on tuple that return correspondent element.
因此,在 Scala 中,您会找到类似Tuple2[T1, T2]or 的类Tuple3[T1, T2, T3],因此对于每个元素,您还有类型参数。集合只接受 1 个类型参数:List[T]. 语法 like("Test", 123, new Date)只是Tuple3[String, Int, Date]. 和_1,_2等只是元组上返回对应元素的字段。
回答by Alex Archambault
You can easily achive that with shapeless:
您可以轻松地achive与无形的:
import shapeless.syntax.std.tuple._
val t = ("a", 2, true, 0.0)
val s = t(0) // String at compile time
val i = t(1) // Int at compile time
// etc
A lot of methods available for standard collection are also available for tuples this way (head, tail, init, last, ++and :::for concatenation, +:and :+for adding elements, take, drop, reverse, zip, unzip, length, toList, toArray, to[Collection], ...)
许多可用于标准集合的方法也可用于元组这种方式(head, tail, init, last,++和:::用于连接,+:以及:+用于添加元素,take, drop, reverse, zip, unzip, length, toList, toArray, to[Collection], ...)
回答by Alex Archambault
With normal index access, any expression can be used, and it would take some serious effort to check at compiletime if the result of the index expression it is guaranteed to be in range. Make it an attribute, and a compile-time error for (1, 2)._3follows "for free". Things like allowing only integer constants inside item access on tuples would be a very special case (ugly and unneeded, some would say ridiculous) and again some work to implement in the compiler.
通过正常的索引访问,可以使用任何表达式,并且在编译时检查索引表达式的结果是否保证在范围内需要一些认真的努力。使它成为一个属性,并且(1, 2)._3“免费”跟随一个编译时错误。像在元组上只允许项目访问中的整数常量之类的事情将是一个非常特殊的情况(丑陋和不需要,有些人会说荒谬)并且在编译器中再次需要一些工作来实现。
Python, for instance, can get away with that because it wouldn't (couldn't) check (at compiletime, that is) if the index is in range anyway.
例如,Python 可以避免这种情况,因为它不会(不能)检查(在编译时,即)索引是否在范围内。
回答by Jay Conrod
I think it's for type checking. As delnan says, if you have a tuple tand an index e(an arbitrary expression), t(e)would give the compiler no information about which element is being accessed (or even if it's a valid element for a tuple of that size). When you access elements by field name (_2is a valid identifier, it's not special syntax), the compiler knows which field you're accessing and what type it has. Languages like Python don't really have types, so this is not necessary for them.
我认为这是用于类型检查。正如德尔南所说,如果您有一个元组t和一个索引e(一个任意表达式),t(e)编译器将无法获得有关正在访问哪个元素的信息(或者即使它是该大小元组的有效元素)。当您按字段名称访问元素时(_2是一个有效的标识符,它不是特殊语法),编译器知道您正在访问哪个字段以及它具有什么类型。像 Python 这样的语言并没有真正的类型,所以这对它们来说不是必需的。
回答by Stefan Endrullis
Apart from the benefits Jean-Philippe Pellet already mentioned this notation is also very common in mathematics (see http://en.wikipedia.org/wiki/Tuple). A lot of lecturers append indexes to tuple variables if they want to referring to the elements of a tuple. And the common (LaTeX) notation for writing "with index n" (referring to the n-th element of the tuple) is _n. So I find it actually very intuitive.
除了让-菲利普·佩莱 (Jean-Philippe Pellet) 已经提到的好处之外,这种符号在数学中也很常见(参见http://en.wikipedia.org/wiki/Tuple)。如果许多讲师想要引用元组的元素,则将索引附加到元组变量。书写“带有索引n”(指元组的第n个元素)的常用 (LaTeX) 符号是_n. 所以我发现它实际上非常直观。

