淺談 Scala 中下劃線的用途

Scala 作爲一門函數式編程語言,對習慣了指令式編程語言的同學來說,會不大習慣,這裏除了思維方式之外,還有語法層面的,比如 underscore(下劃線)就會出現在多種場合,令初學者相當疑惑,今天就來總結下 Scala 中下劃線的用法。

1、存在性類型:Existential types
def foo(l: List[Option[_]]) = ...

2、高階類型參數:Higher kinded type parameters
case class A[K[_],T](a: K[T])

3、臨時變量:Ignored variables
val _ = 5

4、臨時參數:Ignored parameters
List(123) foreach { _ => println("Hi") }

5、通配模式:Wildcard patterns
Some(5match { case Some(_) => println("Yes") }
match {
     case List(1,_,_) => " a list with three element and the first element is 1"
     case List(_*)  => " a list with zero or more elements "
     case Map[_,_] => " matches a map with any key type and any value type "
     case _ =>
 }
val (a, _) = (12)
for (_ <- 1 to 10)

6、通配導入:Wildcard imports
import java.util._

7、隱藏導入:Hiding imports
// Imports all the members of the object Fun but renames Foo to Bar
import com.test.Fun.{ Foo => Bar , _ }

// Imports all the members except Foo. To exclude a member rename it to _
import com.test.Fun.{ Foo => _ , _ }

8、連接字母和標點符號:Joining letters to punctuation
def bang_!(x: Int) = 5

9、佔位符語法:Placeholder syntax
List(123) map (_ + 2)
_ + _   
( (_: Int) + (_: Int) )(2,3)

val nums = List(1,2,3,4,5,6,7,8,9,10)

nums map (_ + 2)
nums sortWith(_>_)
nums filter (_ % 2 == 0)
nums reduceLeft(_+_)
nums reduce (_ + _)
nums reduceLeft(_ max _)
nums.exists(_ > 5)
nums.takeWhile(_ < 8)

10、偏應用函數:Partially applied functions
def fun = {
    // Some code
}
val funLike = fun _

List(123) foreach println _

1 to 5 map (10 * _)

//List("foo", "bar", "baz").map(_.toUpperCase())
List("foo""bar""baz").map(n => n.toUpperCase())

11、初始化默認值:default value
var i: Int = _

12、作爲參數名:
//訪問map
var m3 = Map((1,100), (2,200))
for(e<-m3) println(e._1 + ": " + e._2)
m3 filter (e=>e._1>1)
m3 filterKeys (_>1)
m3.map(e=>(e._1*10, e._2))
m3 map (e=>e._2)

//訪問元組:tuple getters
(1,2)._2

13、參數序列:parameters Sequence 
_*作爲一個整體,告訴編譯器你希望將某個參數當作參數序列處理。例如val s = sum(1 to 5:_*)就是將1 to 5當作參數序列處理。
//Range轉換爲List
List(1 to 5:_*)

//Range轉換爲Vector
Vector(1 to 5: _*)

//可變參數中
def capitalizeAll(args: String*) = {
  args.map { arg =>
    arg.capitalize
  }
}

val arr = Array("what's""up""doc?")
capitalizeAll(arr: _*)

這裏需要注意的是,以下兩種寫法實現的是完全不一樣的功能:

foo _               // Eta expansion of method into method value

foo(_)              // Partial function application

Example showing why foo(_) and foo _ are different:

trait PlaceholderExample {
  def process[A](f: A => Unit)

  val set: Set[_ => Unit]

  set.foreach(process _) // Error 
  set.foreach(process(_)) // No Error
}

In the first case, process _ represents a method; Scala takes the polymorphic method and attempts to make it monomorphic by filling in the type parameter, but realizes that there is no type that can be filled in for A that will give the type (_ => Unit) => ? (Existential _ is not a type).

In the second case, process(_) is a lambda; when writing a lambda with no explicit argument type, Scala infers the type from the argument that foreach expects, and _ => Unit is a type (whereas just plain _ isn't), so it can be substituted and inferred.

This may well be the trickiest gotcha in Scala I have ever encountered.

Refer:

[1] What are all the uses of an underscore in Scala?

http://stackoverflow.com/questions/8000903/what-are-all-the-uses-of-an-underscore-in-scala

[2] Scala punctuation (AKA symbols and operators)

http://stackoverflow.com/questions/7888944/scala-punctuation-aka-symbols-and-operators/7890032#7890032

[3] Scala中的下劃線到底有多少種應用場景?

http://www.zhihu.com/question/21622725

[4] Strange type mismatch when using member access instead of extractor

http://stackoverflow.com/questions/9610736/strange-type-mismatch-when-using-member-access-instead-of-extractor/9610961

[5] Scala簡明教程

http://colobu.com/2015/01/14/Scala-Quick-Start-for-Java-Programmers/


轉載自https://my.oschina.net/leejun2005/blog/405305

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章