现在的位置: 首页 > 综合 > 正文

scala List和Tuple的用法

2013年06月18日 ⁄ 综合 ⁄ 共 3273字 ⁄ 字号 评论关闭


使用
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
是另外一个,诸如此类。


 

抱歉!评论已关闭.