Scala中的列表和元组
来自Martin Odersky的《Scala编程》一书: 另一个有用的容器对象是tuple。像列表一样,元组是不可变的, 但与列表不同,元组可以包含不同类型的元素 但我可以:Scala中的列表和元组,scala,list,tuples,Scala,List,Tuples,来自Martin Odersky的《Scala编程》一书: 另一个有用的容器对象是tuple。像列表一样,元组是不可变的, 但与列表不同,元组可以包含不同类型的元素 但我可以: val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3) for (i <- 0 to 2) { println(oneTwoThreee.apply((i))) } val oneTwoThreee = List(1
val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
for (i <- 0 to 2) {
println(oneTwoThreee.apply((i)))
}
val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
for (i <- 0 to 2) {
println(oneTwoThreee.apply((i)))
}
所以Scala中的列表可以有不同类型的元素
来自同一本书:
您可能想知道为什么不能访问元组的元素
与列表中的元素类似,例如,带有“pair(0)”。原因
列表的apply方法总是返回相同的类型,但每个
元组的元素可以是不同的类型:
但正如上面的代码所示,List.apply()可以返回不同的类型
关于Scala中的列表和元组,我遗漏了什么吗
关于Scala中的列表和元组,我遗漏了什么吗
我认为Odersky试图说明的要点是,每个元组元素都可以包含自己的类型,这允许使用多种不同的类型。由于列表是同质的,列表
不能做的事情,这意味着如果您想要一个列表[Int]
,该列表的所有元素都必须是Int
值
如果查看您创建的列表的类型,您将看到编译器推断出list[Any]
,这是所有Scala类型的公共超类型。这意味着,如果您想对列表中的一个元素做一些具体的事情,即它的head元素的类型是Int
,您不能,因为编译器所知道的关于该元素的所有信息都是它的类型是Any
,您需要了解如何提取底层的“具体”类型:
在使用Tuple3[Int,Int,String]
时,实际上“保留”了具体类型:
scala> val tup = (1, 2, "Third Element")
tup: (Int, Int, String) = (1,2,Third Element)
现在,如果我们想提取一个Int
值并将它们增加1,我们可以:
scala> tup.copy(tup._1 + 1)
res1: (Int, Int, String) = (2,2,Third Element)
如果我们尝试对列表[Any]
执行同样的操作,编译器会理所当然地抱怨:
scala> oneTwoThreee.head + 1
<console>:13: error: type mismatch;
found : Int(1)
required: String
oneTwoThreee.head + 1
^
这将产生:
2
简而言之:
- 在列表中,所有元素都属于同一类型(即使是包含所有元素的任何类型)
- 在元组中,每个元素都有自己的类型
如果你来自例如C的背景,元组就像结构,列表就像数组。一个非常简单的例子,展示了其他答案告诉你的内容
val tuplX = (10, "ten") //tuplX: (Int, String) = (10,ten)
val listX = List(10, "ten") //listX: List[Any] = List(10, ten)
tuplX._1 - 6 //res0: Int = 4
tuplX._2.length //res1: Int = 3
listX(0) - 6 //Error: value - is not a member of Any
listX(1).length //Error: value length is not a member of Any
但我可以:
val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
for (i <- 0 to 2) {
println(oneTwoThreee.apply((i)))
}
val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
for (i <- 0 to 2) {
println(oneTwoThreee.apply((i)))
}
所以Scala中的列表可以有不同类型的元素
不,不能。列表的类型是list[Any]
,因此所有元素的类型都相同:Any
如果在Scala REPL中键入代码,它将在每一步告诉您代码的类型:
scala> val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
oneTwoThreee: List[Any] = List(1, 2, Third Element)
↑↑↑↑↑↑↑↑↑
oneTwoThreee(0)
//=> res: Any = 1
// ↑↑↑
oneTwoThreee(1)
//=> res: Any = 2
// ↑↑↑
oneTwoThreee(2)
//=> res: Any = Third Element
// ↑↑↑
您也可以向Scala REPL询问类型:
scala> :type oneTwoThreee
List[Any]
是一种非常通用的类型,因此非常无用,因为它没有任何“有趣”的方法。事实上,使用Any
:,您所做的几乎是唯一可以做的事情。这就是为什么你没有注意到这个问题,你碰巧选了唯一有效的东西
尝试将列表的第一个和第二个元素相乘:
oneTwoThreee(0) * oneTwoThreee(1)
// error: value * is not a member of Any
oneTwoThreee(0) * oneTwoThreee(1)
^
您可能想知道为什么不能访问元组的元素
与列表中的元素类似,例如,带有“pair(0)”。原因
列表的apply方法总是返回相同的类型,但每个
元组的元素可以是不同的类型:
但正如上面的代码所示,List.apply()可以返回不同的类型
不,不能。让我们再次询问Scala REPL的类型:
scala> val oneTwoThreee = List(1, 2, "Third Element") //same as:List.apply(1,2,3)
oneTwoThreee: List[Any] = List(1, 2, Third Element)
↑↑↑↑↑↑↑↑↑
oneTwoThreee(0)
//=> res: Any = 1
// ↑↑↑
oneTwoThreee(1)
//=> res: Any = 2
// ↑↑↑
oneTwoThreee(2)
//=> res: Any = Third Element
// ↑↑↑
如您所见,类型始终相同:
Any
只是一个注释。如果您得到List元素的类名,Scala就会知道它的类型。可能是类型推断
scala> val l = List(1,2,3,"Adriano Avelar")
val l: List[Any] = List(1, 2, 3, Adriano Avelar)
scala> print(l(3).getClass.getSimpleName)
String
scala> print(l(2).getClass.getSimpleName)
Integer