8.3 使用Map
之前,我们用Set
存储RSS源。假定我们想把作者的名字同RSS源关联起来,可以将其按照键值对的方式存储在Map
里:
val feeds = Map("Andy Hunt" -> "blog.toolshed.com",
"Dave Thomas" -> "pragdave.pragprog.com",
"Dan Steinberg" -> "dimsumthinking.com/blog")
如果想找出作者名字以“D”开头的RSS源,可以用filterKeys()
方法:
val filterNameStartWithD = feeds filterKeys( _ startsWith "D" )
println("# of Filtered: " + filterNameStartWithD.size)
结果如下:
# of Filtered: 2
另一方面,如果要根据值进行过滤,取代键值过滤,或是跟键值过滤一起使用可以用filter()
方法。提供给filter()
的函数值接收一个(key, value)
的元组,像下面例子这样:
val filterNameStartWithDAndBlogInFeed = feeds filter { element =>
val (key, value) = element
(key startsWith "D") && (value contains "blog")
}
println("# of feeds with auth name D* and blog in URL: " +
filterNameStartWithDAndBlogInFeed.size)
输出如下:
# of feeds with auth name D* and blog in URL: 1
如果要获得一个人的RSS源,用get()
即可。由于给定的键值可能没有对应的值,所以get()
的返回类型是Option[T]
,结果可能是Some[T]
或是None
,其中T
是Map
里值的类型:
println("Get Andy's Feed: " + feeds.get("Andy Hunt"))
println("Get Bill's Feed: " + feeds.get("Bill Who"))
上面代码的输出如下:
Get Andy's Feed: Some(blog.toolshed.com)
Get Bill's Feed: None
另外,还可以用apply()
方法获取一个键值对应的值——记住,对类或对象使用括号时,Scala调用的就是这个方法。不过,apply()
方法返回的不是Option[T]
,而是值。不同于get()
,如果给定的键值没有对应的值,就会抛出异常。所以,请确保代码放到了一个try-catch
块里:
try {
println("Get Andy's Feed Using apply(): " + feeds("Andy Hunt"))
print("Get Bill's Feed: ")
println(feeds("Bill Who"))
}
catch {
case ex : java.util.NoSuchElementException => println("Not found")
}
使用apply()
的输出如下:
Get Andy's Feed Using apply(): blog.toolshed.com
Get Bill's Feed: Not found
如果想添加一个RSS源,可以用update()
方法。因为我们用的是一个不变容器,update()
并不会影响原来的Map
。相反,它会返回一个新的Map
,包含了新增的元素:
val newFeeds1 = feeds.update("Venkat Subramaniam", "agiledeveloper.
com/blog")
println("Venkat's blog in original feeds: " + feeds.get("Venkat
Subramaniam"))
println("Venkat's blog in new feed: " + newFeeds1("Venkat Subramaniam"))
看一下update()
的效果:
Venkat's blog in original feeds: None
Venkat's blog in new feed: agiledeveloper.com/blog
相对于显式调用update()
,还可以利用另一个Scala魔法。如果对赋值左边的类或实例使用括号,Scala会自动调用update()
方法。所以,X() = b
等价于X.update(b)
。如果update()
的参数多于一个,可以将除了最后一个参数之外的所有参数放到括号里。所以,X(a) = b
等价于X.update(a, b)
。
可以像这样对不变容器使用隐式调用:val newFeed = feeds("author") = "blog"
。不过,这样做会因为多重赋值(一个是update()
,另一个保存了新建的Map
)而丢弃了语义的优雅。如果要从方法里返回一个新建的Map
,隐式的update()
用起来会很优雅。不过,如果要就地更新Map
,使用可变容器隐式调用会更有意义一些。
val mutableFeeds = scala.collection.mutable.Map(
"Scala Book Forum" -> "forums.pragprog.com/forums/87")
mutableFeeds("Groovy Book Forum")= "forums.pragprog.com/forums/55"
println("Number of forums: " + mutableFeeds.size)
输出如下:
Number of forums: 2