Scala的一些语法技巧
1. 多参数列表
Scala 允许你指明函数的最后一个参数可以是重复的。这可以允许客户向函数传入可变长度参数列表。想要标注一个重复参数,在参数的类型之后加一个 *
。例如:
def echo(args: String*) = { for (arg <- args) println(arg) }
这样定义, echo 可以被零个至多个 String 参数调用
echo() echo("one") echo("hello", "world")
函数内部,重复参数的类型是声明参数类型的数组。因此, echo 函数里被声明为类型“ String* ”
的 args 的类型实际上是 Array[String] 。然而,如果你有一个合适类型的数组,并尝试把它当作
重复参数传入,你会得到一个编译器错误:
val arr = Array("I`m", "from", "China") echo(arr) # 编译报错 error: type mismatch; found : Array[java.lang.String] required: String
要实现这个做法,你需要在数组参数后添加 : _*
符号,像这样:
val arr = Array("I`m", "from", "China") echo(arr: _*)
这个标注 : _*
告诉编译器把 arr 的每个元素当作参数,而不是当作单一的参数传给 echo 。
2. Tuple2与Map
Map(1->"a", 2->"b").map { case (i, j)=> (1, j) } res0: scala.collection.immutable.Map[Int,String] = Map(1 -> b)
如果map中返回的是Tuple2类型, 那么最后结果会转化成Map, 同时相同的key会被覆盖掉
Map(1->"a", 2->"b").map { case (i, j)=> (1, 1, j) } res3: scala.collection.immutable.Iterable[(Int, Int, String)] = List((1,1,a), (1,1,b))
如果map中返回的不是Tuple2类型, 那么最后结果就是List而不是Map, 此时就不必担心数据被覆盖的问题了
3. Java集合与Scala集合相互转换
在 scala.collection.convert
包下定义了常用的一些隐式转换类
import java.util import scala.collection.convert.ImplicitConversionsToScala._ import scala.collection.convert.ImplicitConversionsToJava._ object CommonImplicit { implicit def map2ScalaMap[K, V](map: util.Map[K, V]): Map[K, V] = `map AsScala`(map).toMap implicit def list2ScalaList[T](list: util.List[T]): List[T] = `list asScalaBuffer`(list).toList implicit def map2JavaMap[K, V](map: Map[K, V]): util.Map[K, V] = `map AsJavaMap`(map) implicit def map2JavaList[T](list: List[T]): util.List[T] = `seq AsJavaList`(list) }
在使用时直接 import CommonImplicit._
即可
4. reduce与foldLeft
reduce: 对集合元素进行归约操作, 默认从左到右两两运算, 然后结果与右边的元素继续运算, 最终得到结果
scala> List[Int]().reduce(_ + _) scala> java.lang.UnsupportedOperationException: empty.reduceLeft at scala.collection.LinearSeqOptimized.reduceLeft(LinearSeqOptimized.scala:139)
查看源码发现reduce默认调用reduceLeft, 而reduceLeft会判断集合是否为空, 如果是则抛出异常
上图我们可以看到reduceLeft实际调用的是foldLeft, 所以这时候需要用foldLeft来代替reduceLeft
因为集合为空, 所以我们需要给一个初始的head填充到原来的集合中:
scala> List[Int]().foldLeft(0)(_ + _) 等价于 scala> List[Int](0).reduce(_ + _)