附上Effective Scala:Effective Scala
学习笔记摘抄于Twitter scala文档:Twitter.github.io
为了方便,本文中类的定义代码和调用代码同放一处;
实际上,代码的调用需要写在程序入口(main方法)
一、Basic Data Structures
Arrays
Arrays preserve order, can contain duplicates, and are mutable.(有序,可重复,可修改)
val numbers = Array(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
val two = numbers(1)
Lists
Lists preserve order, can contain duplicates, and are immutable.(有序,可重复,不可修改)
val numbers = List(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
numbers(3) = 10
:9: error: value update is not a member of List[Int]
numbers(3) = 10
Sets
Sets do not preserve order and have no duplicates.(无序,不重复)
val numbers = Set(1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
println(numbers) //Set(5, 1, 2, 3, 4)
Tuple
A tuple groups together simple logical collections of items without using a class.
Unlike case classes, they don’t have named accessors, instead they have accessors that are named by their position and is 1-based rather than 0-based.(下标从1开始)
val hostPort = ("localhost", 80)
val host = hostPort._1
val port = hostPort._2
Tuples fit with pattern matching nicely.
hostPort match {
case ("localhost", port) => ...
case (host, port) => ...
}
Tuple has some special sauce for simply making Tuples of 2 values:->
val t = 1 -> 2
println(t) //(1,2)
Maps
Map(1 -> 2, 2 -> 3) //or Map((1,2), (2,3))
Map("foo" -> "bar")
Map(1 -> Map("foo" -> "bar")) //value is a map
Map("timesTwo" -> { timesTwo(_) }) //value is a function
This looks like special syntax but remember back to our discussion of Tuple that ->
can be used to create Tuples.
Option
Option
is a container that may or may not hold something.
The basic interface for Option looks like:
trait Option[T] {
def isDefined: Boolean
def get: T
def getOrElse(t: T): T
}
Option itself is generic and has two subclasses: Some[T]
or None
val numbers = Map("one" -> 1, "two" -> 2)
val res = numbers.get("two") //Some(2)
val res1 = numbers.get("Two") //None
getOrElse
lets you easily define a default value.
val result = res1.getOrElse(0) * 2
二、Functional Combinators(组合子)
map
Evaluates a function over each element in the list, returning a list with the same number of elements.
val numbers = List(1, 2, 3, 4)
numbers.map((i: Int) => i * 2)
def timesTwo(i: Int): Int = i * 2
numbers.map(timesTwo) //pass in a function
foreach
foreach
is like map but returns nothing. foreach is intended for side-effects only.
numbers.foreach((i: Int) => i * 2)
filter
removes any elements where the function you pass in evaluates to false. Functions that return a Boolean are often called predicate(谓语) functions.
val newNumbers = numbers.filter((i: Int) => i % 2 == 0) //List(2, 4)
def isEven(i: Int): Boolean = i % 2 == 0
numbers.filter(isEven)
zip
zip
aggregates the contents of two lists into a single list of pairs.
List(1, 2, 3).zip(List("a", "b", "c")) //List((1,a), (2,b), (3,c))
partition
partition
splits a collection based on where it falls with respect to a predicate function.
partition将使用给定的谓词函数分割列表。
val numbers = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
numbers.partition(_ % 2 == 0)) //(List(2, 4, 6, 8, 10),List(1, 3, 5, 7, 9))
find
find returns the first element of a collection that matches a predicate function.
numbers.find((i: Int) => i > 5) //Some(6)
drop & dropWhile
drop
drops the first i elements
dropWhile
removes the first elements that match a predicate function. For example, if we dropWhile odd numbers from our list of numbers, 1 gets dropped (but not 3 which is “shielded” by 2).
dropWhile
将删除元素直到找到第一个匹配谓词函数的元素。例如,如果我们在numbers列表上使用dropWhile奇数的函数, 1将被丢弃(但3不会被丢弃,因为他被2“保护”了)。
numbers.drop(5) //List(6, 7, 8, 9, 10)
numbers.dropWhile(_ % 2 != 0) //List(2, 3, 4, 5, 6, 7, 8, 9, 10)
foldLeft
numbers.foldLeft(0)((m: Int, n: Int) => m + n) //55
0 is the starting value (Remember that numbers is a List[Int]), and m
acts as an accumulator.
scala> numbers.foldLeft(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n }
m: 0 n: 1
m: 1 n: 2
m: 3 n: 3
m: 6 n: 4
m: 10 n: 5
m: 15 n: 6
m: 21 n: 7
m: 28 n: 8
m: 36 n: 9
m: 45 n: 10
res0: Int = 55
foldRight
Is the same as foldLeft except it runs in the opposite direction.
scala> numbers.foldRight(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n); m + n }
m: 10 n: 0
m: 9 n: 10
m: 8 n: 19
m: 7 n: 27
m: 6 n: 34
m: 5 n: 40
m: 4 n: 45
m: 3 n: 49
m: 2 n: 52
m: 1 n: 54
res0: Int = 55
flatten
flatten collapses one level of nested structure.
List(List(1, 2), List(3, 4)).flatten //List(1, 2, 3, 4)
flatMap
flatMap
is a frequently used combinator that combines mapping and flattening. flatMap
takes a function that works on the nested lists and then concatenates the results back together.
val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers.flatMap(x => x.map(_ * 2)) //List(2, 4, 6, 8)
nestedNumbers.map((x: List[Int]) => x.map(_ * 2)).flatten ////List(2, 4, 6, 8)
Think of it as short-hand for mapping and then flattening.
Generalized functional combinators
Interestingly, every functional combinator shown above can be written on top of fold
.
def ourMap(numbers: List[Int], fn: Int => Int): List[Int] = {
numbers.foldRight(List[Int]()) { (x: Int, xs: List[Int]) =>
fn(x) :: xs
}
}
ourMap(numbers, timesTwo(_)) //List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
Why List[Int]()
? Scala wasn’t smart enough to realize that you wanted an empty list of Ints to accumulate into.
Maps?
All of the functional combinators shown work on Maps, too
Map
可以被看作是一个二元组的列表,所以你写的函数要处理一个键和值的二元组。
val extensions = Map("steve" -> 100, "bob" -> 101, "joe" -> 201)
extensions.filter((namePhone: (String, Int)) => namePhone._2 < 200) //Map((steve,100), (bob,101))
extensions.filter({case (name, extension) => extension < 200}) //Map((steve,100), (bob,101))