hangscer

使用容器

2017/02/11

8.使用容器

Scala常见的容器有:ListSetVectorMap
两个包:

  • scala.collection.mutable
  • scala.collection.immutable

默认包含的Predef对象为SetMap提供的别名指向了不可变实现。

工厂方法,如Set(1,2,3),类似的X(......),其中X是类名或者实例引用,会当做X.apply(......)。这样,如果类的伴生对象有apply方法的话,Scala会自动调用。

8.2 使用Set

把RSS源存放于Set集合中:

1
2
3
4
5
6
7
8
9
10
val feeds1=Set("blog.toolshed.com","pragdave.pragprog.com","pragmctic-osxer.blogspot.com","pragmctic-osxer.blogspot.com")
val feeds2=Set("blog.tooshed.com","martianfowler.com/bliki")
println(feeds1 & feeds2)
//交集
println(feeds1 ++ feeds2)
//并集
println(feeds1.map("http://"+_).toList)
//map
println(feeds1.foreach(println))
//迭代

8.3 使用Map

RSS作者和RSS源关联起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val feeds=Map("Andy Hunt"->"blog.toolshed.com",
"Dave Thomas"->"pragdave.pragprog.com",
"Dan Steinberg"->"dimsumthinking.com/blog")
println(feeds.filterKeys(_ startsWith("D")))
println(feeds.filter( tuple=>tuple._1.startsWith("A")||tuple._2.startsWith("d") ))
println(feeds.get("Andy Hunt"))
println(feeds.get("sadad"))
println(feeds("Andy Hunt"))
println(feeds.updated("蒋航", "哈哈哈哈哈哈"))
val mutableFeeds=scala.collection.mutable.Map(
"蒋航"->"😄")
println(mutableFeeds)
println(mutableFeeds.updated("小韩", "ok😊"))
println(mutableFeeds)

8.4 使用List

SetMap都是mutableimmutable实现,List和它们不同,只有immutable
Scala访问List第一个元素容易快速。
访问最后一个元素要遍历整个List,代价很大。
List大部分操作都是围绕headtail展开的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
val feeds=List("blog","pragdave","蒋航")
println(feeds.head)
// feeds(0) as well
println("xiaohan"::feeds)
//含义:在list前加上元素a 得到新的list ::操作是list操作 虽然list在操作符之后
println(List("12","23")::feeds)
//List(List(12, 23), blog,pragdave, 蒋航)
println(12::23::feeds)
//List(12, 23, blog,pragdave, 蒋航)
println(List("12","23") ::: feeds)
//List(12, 23, blog,pragdave, 蒋航)
//把元素或者另一个list加到某个list后面,实际上应该调用后面的list的前缀运算符,因为访问list的head元素更快
//flodLeft
val numbers=List(1,2,3,4,5,6,7,8,9,10)
println( numbers.foldLeft(0)(_+_) )
// (0 /: numbers)(_+_)

方法命名约定

方法名的第一个字符决定了优先级。
而接下来,会发现方法名最后一个字也有作用——它决定了方法调用的目标。
:的约定让人惊奇,习惯就好(开启“开启Scala之眼”)
比如,在List前面添加一个值,可以写作value::list,读作“在List前添加value”
但是你仍然可以这样写:list.::(value)
除了以:结尾的运算符,还有一套也是其后的实例为目标的,包括一元运算符!``、等。
会映射为unary_+()调用。

1
2
3
4
5
6
7
8
9
10
class Sample{
def unary_+ = println("hahah")
def unary_- = "ok"
}
val s=new Sample
+s
//println
println(-s)
//"ok"
//开启Scala之眼

8.5 for表达式

foreach内部迭代——你不必控制循环
外部迭代——for循环:
for( i<- 1 to 3 ){ println("ho") }
通用语法形式:

1
2
for( [pattern <- generator;definition*]+ filter* )
  [yield] expression

for表达式接收参数有一个或者多个生成器,0个或者多个定义,还有0个或者多个过滤器filteryield关键字可选。

先从yield开始。假定要取出一个范围内的系列值,每个值乘以2。

1
2
3
4
5
6
val result=for( i<- 1 to 10 ) yield i*2
println(result)
//Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
val result2=(1 to 10).map(_*2)
println(result2)
//Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

幕后,Scala会把for翻译为另外一个表达式。(for生成器表达式也是语法糖)
现在只对一定范围内的偶数翻倍,使用过滤器:

1
2
3
4
5
val doubleEven=for{
i<- 1 to 10
if %2==0} yield i*2
println(doubleEven)
//Vector(4, 8, 12, 16, 20)

在函数式编程里,称为list comprehension
还可以把括号换成大括号。
多个生成器——多重循环。

1
2
3
4
5
for (i<-1 to 3 ;j<-5 to 9){
//多重循环
println(i,j)
// (1,5)(1,6)(2,5)(2,6)(3,5)(3,6)
}