scala List和Tuple的用法

使用 List

方法不应该有副作用是函数风格编程的一个很重要的理念。方法唯一的效果应该是计算并返回值。用这种方式工作的好处就是方法之间很少纠缠在一起,因此就更加可靠和可重用。另一个好处(静态类型语言里)是传入传出方法的所有东西都被类型检查器检查,因此逻辑错误会更有可能把自己表现为类型错误。把这个函数式编程的哲学应用到对象世界里意味着使对象不可变。

如你所见, Scala 数组是一个所有对象都共享相同类型的可变序列。比方说 Array[String] 仅包含 String 。尽管实例化之后你无法改变 Array 的长度,它的元素值却是可变的。因此, Array 是可变的对象。

说到共享相同类型的不可变对象序列, Scala List 类才是。和数组一样, List[String] 包含的仅仅是 String Scala List scala.List ,不同于 Java java.util.List ,总是不可变的(而 Java List 可变)。更通常的说法, Scala List 是设计给函数式风格的编程用的。创建一个 List 很简单。代码 3.3 做了展示:

val oneTwoThree = List(1, 2, 3)

代码 3.3 创造和初始化列表

代码 3.3 中的代码完成了一个新的叫做 oneTwoThree val ,并已经用带有整数元素值 1 2 3 的新 List[Int] 初始化。 3 因为 List 是不可变的,他们表现得有些像 Java String :当你在一个 List 上调用方法时,似乎这个名字指代的 List 看上去被改变了,而实际上它只是用新的值创建了一个 List 并返回。比方说, List 有个叫 ::: 的方法实现叠加功能。你可以这么用:

val oneTwo = List(1, 2)

val threeFour = List(3, 4)

val oneTwoThreeFour = oneTwo ::: threeFour

println(oneTwo + " and " + threeFour + " were not mutated.") 3 Scala 的下一步 46

println("Thus, " + oneTwoThreeFour + " is a new List.")

如果你执行这个脚本,你会看到:

List(1, 2) and List(3, 4) were not mutated.

Thus, List(1, 2, 3, 4) is a new List.

或许 List 最常用的操作符是发音为 cons :: Cons 把一个新元素组合到已有 List 的最前端,然后返回结果 List 。例如,若执行这个脚本:

val twoThree = list(2, 3)

val oneTwoThree = 1 :: twoThree

println(oneTwoThree)

你会看到:

List(1, 2, 3)

注意

表达式 1 :: twoThree 中, :: 是它右操作数,列表 twoThree ,的方法。你或许会疑惑 :: 方法的关联性上有什么东西搞错了,不过这只是一个简单的需记住的规则:如果一个方法被用作操作符标注,如 a * b ,那么方法被左操作数调用,就像 a.*(b) 除非方法名以冒号结尾。这种情况下,方法被右操作数调用。因此, 1 :: twoThree 里, :: 方法被 twoThree 调用,传入 1 ,像这样: twoThree.::(1)

由于定义空类的捷径是 Nil ,所以一种初始化新 List 的方法是把所有元素用 cons 操作符串起来, Nil 作为最后一个元素。 4 比方说,下面的脚本将产生与之前那个同样的输出, List(1, 2, 3)

4 要在最后用到 Nil 的理由是 :: 是定义在 List 类上的方法。如果你想只是写成 1 :: 2 :: 3 ,由于 3 Int 类型,没有 :: 方法,因此会导致编译失败。

val oneTwoThree = 1 :: 2 :: 3 :: Nil

println(oneTwoThree)

Scala List 包装了很多有用的方法,表格 3.1 罗列了其中的一些。列表的全部实力将在第十六章释放。

为什么列表不支持 append

List 没有提供 append 操作,因为随着列表变长 append 的耗时将呈线性增长,而使用 :: 做前缀则仅花费常量时间。如果你想通过添加元素来构造列表,你的选择是把它们前缀进去,当你完成之后再调用 reverse ;或使用 ListBuffer ,一种提供 append 操作的可变列表,当你完成之后调用 toList ListBuffer 将在 22.2 节中描述。

类型 List 的一些方法和作用 方法名

方法作用

List() Nil

List

List("Cool", "tools", "rule)

创建带有三个值 "Cool" "tools" "rule" 的新 List[String]

val thrill = "Will"::"fill"::"until"::Nil

创建带有三个值 "Will" "fill" "until" 的新 List[String]

List("a", "b") ::: List("c", "d")

叠加两个列表(返回带 "a" "b" "c" "d" 的新 List[String]

thrill(2)

返回在 thrill 列表上索引为 2 (基于 0 )的元素(返回 "until"

thrill.count(s => s.length == 4)

计算长度为 4 String 元素个数(返回 2

thrill.drop(2)

返回去掉前 2 个元素的 thrill 列表(返回 List("until")

thrill.dropRight(2)

返回去掉后 2 个元素的 thrill 列表(返回 List("Will")

thrill.exists(s => s == "until")

判断是否有值为 "until" 的字串元素在 thrill 里(返回 true

thrill.filter(s => s.length == 4)

依次返回所有长度为 4 的元素组成的列表(返回 List("Will", "fill")

thrill.forall(s => s.endsWith("1"))

辨别是否 thrill 列表里所有元素都以 "l" 结尾(返回 true

 

使用 Tuple

另一种有用的容器对象是 元组: tuple 。与列表一样,元组也是不可变的,但与列表不同,元组可以包含不同类型的元素。而列表应该是 List[Int] List[String] 的样子,元组可以同时拥有 Int String 。元组很有用,比方说,如果你需要在方法里返回多个对象。 Java 里你将经常创建一个 JavaBean 样子的类去装多个返回值, Scala 里你可以简单地返回一个元组。而且这么做的确简单:实例化一个装有一些对象的新元组,只要把这些对象放在括号里,并用逗号分隔即可。一旦你已经实例化了一个元组,你可以用点号,下划线和一个基于 1 的元素索引访问它。代码 3.4 展示了一个例子:

val pair = (99, "Luftballons")

println(pair._1)

println(pair._2)

代码 3.4 创造和使用元组

代码 3.4 的第一行,你创建了元组,它的第一个元素是以 99 为值的 Int ,第二个是 "luftballons" 为值的 String Scala 推断元组类型为 Tuple2[Int, String] ,并把它赋给变量 pair 。第二行,你访问 _1 字段,从而输出第一个元素, 99 。第二行的这个 . 与你用来访问字段或调用方法的点没有区别。本例中你正用来访问名叫 _1 的字段。如果执行这个脚本,你能看到:

99

Luftballons

元组的实际类型取决于它含有的元素数量和这些元素的类型。因此, (99, "Luftballons") 的类型是 Tuple2[Int, String] ('u', 'r', 'the', 1, 4, "me") Tuple6[Char, Char, String, Int, Int, String]  

  尽管理论上你可以创建任意长度的元组,然而当前 Scala 库仅支持到 Tupe22


你或许想知道为什么你不能像访问 List 里的元素那样访问元组的,就像 pair(0) 。那是因为 List apply 方法始终返回同样的类型,但是元组里的或许类型不同。 _1 可以有一个结果类型, _2 是另外一个,诸如此类。

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值