天天看點

scala 下劃線使用指南

原文位址: https://my.oschina.net/joymufeng/blog/863823   作者: joymufeng 下劃線這個符号幾乎貫穿了任何一本Scala程式設計書籍,并且在不同的場景下具有不同的含義,繞暈了不少初學者。正因如此,下劃線這個特殊符号無形中增加Scala的入門難度。本文希望幫助初學者踏平這個小山坡。

1、用于替換Java的等價文法

由于大部分的Java關鍵字在Scala中擁有了新的含義,是以一些基本的文法在Scala中稍有變化。

1.1 導入通配符

*在Scala中是合法的方法名,是以導入包時要使用_代替。

//Java
import java.util.*;

//Scala
import java.util._           

1.2 類成員預設值

Java中類成員可以不賦初始值,編譯器會自動幫你設定一個合适的初始值:

class Foo{
     //String類型的預設值為null
     String s;
}           

而在Scala中必須要顯式指定,如果你比較懶,可以用_讓編譯器自動幫你設定初始值:

class Foo{
    //String類型的預設值為null
    var s: String = _
}           

該文法隻适用于類成員,而不适用于局部變量。

1.3 可變參數

Java聲明可變參數如下:

public static void printArgs(String ... args){
    for(Object elem: args){
        System.out.println(elem + " ");
    }
}           

調用方法如下:

//傳入兩個參數
printArgs("a", "b");
//也可以傳入一個數組
printArgs(new String[]{"a", "b"});           

在Java中可以直接将數組傳給printArgs方法,但是在Scala中,你必須要明确的告訴編譯器,你是想将集合作為一個獨立的參數傳進去,還是想将集合的元素傳進去。如果是後者則要借助下劃線:

printArgs(List("a", "b"): _*)           

1.4 類型通配符

Java的泛型系統有一個通配符類型,例如List

public static void printList(List<?> list){
    for(Object elem: list){
        System.out.println(elem + " ");
    }
}           

對應的Scala版本為:

def printList(list: List[_]): Unit ={
   list.foreach(elem => println(elem + " "))
}           

2、模式比對

2.1 預設比對

str match{
    case "1" => println("match 1")
    case _   => println("match default")
}           

2.2 比對集合元素

//比對以0開頭,長度為三的清單
expr match {
  case List(0, _, _) => println("found it")
  case _ =>
}

//比對以0開頭,長度任意的清單
expr match {
  case List(0, _*) => println("found it")
  case _ =>
}

//比對元組元素
expr match {
  case (0, _) => println("found it")
  case _ =>
}

//将首元素指派給head變量
val List(head, _*) = List("a")           

3、 Scala特有文法

類型通配符

public static void printList(List<?> list){
    for(Object elem: list){
        System.out.println(elem + " ");
    }
}           

3.1 通路Tuple元素

val t = (1, 2, 3)
println(t._1, t._2, t._3)           

3.2 簡寫函數字面量(function literal)

如果函數的參數在函數體内隻出現一次,則可以使用下劃線代替:

val f1 = (_: Int) + (_: Int)
//等價于
val f2 = (x: Int, y: Int) => x + y

list.foreach(println(_))
//等價于
list.foreach(e => println(e))

list.filter(_ > 0)
//等價于
list.filter(x => x > 0)           

3.3 定義一進制操作符

在Scala中,操作符其實就是方法,例如1 + 1等價于1.+(1),利用下劃線我們可以定義自己的左置操作符,例如Scala中的負數就是用左置操作符實作的

-2
//等價于
2.unary_-           

3.4 定義指派操作符

我們通過下劃線實作指派操作符,進而可以精确地控制指派過程:

class Foo {
  def name = { "foo" }
  def name_=(str: String) {
    println("set name " + str)
  }
}
val m = new Foo()
m.name = "Foo" //等價于: m.name_=("Foo")           

3.5 定義部分應用函數(partially applied function)

我們可以為某個函數隻提供部分參數進行調用,傳回的結果是一個新的函數,即部分應用函數。因為隻提供了部分參數,是以部分應用函數也是以而得名。

def sum(a: Int, b: Int, c: Int) = a + b + c
val b = sum(1, _: Int, 3)
b: Int => Int = <function1>
b(2) //6           

3.6 将方法轉換成函數

Scala中方法和函數是兩個不同的概念,方法無法作為參數進行傳遞,也無法指派給變量,但是函數是可以的。在Scala中,利用下劃線可以将方法轉換成函數:

//将println方法轉換成函數,并指派給p
val p = println _  
//p: (Any) => Unit           

4、小結

下劃線在大部分的應用場景中是以文法糖的形式出現的,可以減少擊鍵次數,并且代碼顯得更加簡潔。但是對于不熟悉下劃線的同學閱讀起來稍顯困難,希望通過本文能夠幫你解決這個的困惑。