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会判断集合是否为空, 如果是则抛出异常

Scala的一些语法技巧

上图我们可以看到reduceLeft实际调用的是foldLeft, 所以这时候需要用foldLeft来代替reduceLeft
因为集合为空, 所以我们需要给一个初始的head填充到原来的集合中:

scala> List[Int]().foldLeft(0)(_ + _)
等价于
scala> List[Int](0).reduce(_ + _)

相关推荐