• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

Scala 变长参数之*与:_*

互联网 diligentman 2周前 (11-21) 9次浏览

1.引言

编写函数时经常遇到参数长度不一致的情况,例如我想把传入的每个参数合成一个字符串,或者把传入的几个参数加在一起求和,当然也可以使用ArrayBuffer进行传参,但是每次传参都需要先append再传入,扩展性不好,这时候就需要变长参数

 

2.不定长参数 *

下面两个例子就是上面引言中的实现,他支持传入多个参数,达到我们的需求。

  def toLog(args: String*): String = {
    args.mkString("t")
  }
  def sum(nums: Int*): Int = {
    var total = 0
    nums.foreach(num => total += num)
    total
  }
    println(toLog("a","b","c","d","e"))
    println(sum(1,2,3,4,5))

写成ArrayBuffer显得不那么简洁:

  def toLog(args: ArrayBuffer[String]): String = {
    args.mkString("t")
  }
  val args = ArrayBuffer("0","1","2","3","4")
  println(toLog(args))

 

3.不定长参数伴侣 :_*

:_*参数为了适配 *而设计,假设我们有一个Int的seq想要调用sum

    println(sum(1 to 5))

这么直接传入是不可以的,参数不一致,但是可以使用 :_*,他会告诉函数将传入的seq的每个元素当做参数处理,从而不会报出类型不一致:

    println(sum(1 to 5:_*))

当然直接使用不可以:

    val num = 1 to 5:_*

Scala 变长参数之*与:_*

编译器提示这里:_*只允许在*的参数模式下使用。

 

4.:_*的其他场景

=> 不可变map转换为可变map

    val immuHashMap = scala.collection.immutable.HashMap(1->"a",2->"b") // 不可变hashmap
    // immutable.HashMap to mutable.HashMap
    val immu2mu = scala.collection.mutable.HashMap(immuHashMap.toSeq:_*)

这里不可变map转换为可变map就是利用了:_*的特性,是因为底层有一个GenMapFactory类构建了map的Apply方法且使用了 * 参数,同时这里使用了泛型:

abstract class GenMapFactory[CC[A, B] <: GenMap[A, B] with GenMapLike[A, B, CC[A, B]]] {

  /** The type constructor of the collection that can be built by this factory */
  type Coll = CC[_, _]

  /** An empty $Coll */
  def empty[A, B]: CC[A, B]

  /** A collection of type $Coll that contains given key/value bindings.
   *  @param elems   the key/value pairs that make up the $coll
   *  @tparam A      the type of the keys
   *  @tparam B      the type of the associated values
   *  @return        a new $coll consisting key/value pairs given by `elems`.
   */
  def apply[A, B](elems: (A, B)*): CC[A, B] = (newBuilder[A, B] ++= elems).result()

  /** The default builder for $Coll objects.
   *  @tparam A      the type of the keys
   *  @tparam B      the type of the associated values
   */
  def newBuilder[A, B]: Builder[(A, B), CC[A, B]] = new MapBuilder[A, B, CC[A, B]](empty[A, B])

  /** The standard `CanBuildFrom` class for maps.
   */
  class MapCanBuildFrom[A, B] extends CanBuildFrom[Coll, (A, B), CC[A, B]] {
    def apply(from: Coll) = newBuilder[A, B]
    def apply() = newBuilder
  }
}

核心就是 def apply[A, B](elems: (A, B)*): CC[A, B] = (newBuilder[A, B] ++= elems).result(),CC代表map的泛型,A、B代表key、value的泛型,这里Apply方法参数是(A,B)*,所以支持我们使用:_*一下输入很多kv对进行初始化,只不过比我们初始化一个新的可变map再把不可变map的kv设置进去trick一些。

 

=> 变量声明

    val arr = Array(1,2,3,4,5)
    val Array(first, second, _*) = arr

当只需要声明部分变量,其余位置不想全写时可以采用_*代替其他参数,当然极端情况下也可以用通配符替代所有参数,只不过这样做没有意义:

    val Array(_*) = arr

上面可以看做是Array的 * apply方法,下面则是上述函数的真实状态,用五个通配符代替五个参数。  其实也比较好理解,_代表通配符,_*加一个星号就代表可变长度通配符就有很多很多通配符啦

    val Array(_,_,_,_,_) = arr

 


喜欢 (0)