Scala基礎(chǔ) - 下劃線使用指南

歡迎來(lái)訪PlayScala社區(qū)(http://www.playscala.cn/)

毫不夸張的說(shuō),下劃線這個(gè)符號(hào)貫穿了任何一本Scala編程書籍,并且在不同的場(chǎng)景下具有不同的含義,繞暈了不少初學(xué)者。正因如此,下劃線這個(gè)特殊符號(hào)無(wú)形中增加Scala的入門難度。本文希望幫助初學(xué)者踏平這個(gè)小山坡。

1. 用于替換Java的等價(jià)語(yǔ)法

由于大部分的Java關(guān)鍵字在Scala中擁有了新的含義,所以一些基本的語(yǔ)法在Scala中稍有變化。

1.1 導(dǎo)入通配符

*在Scala中是合法的方法名,所以導(dǎo)入包時(shí)要使用_代替。

//Java
import java.util.*;

//Scala
import java.util._

1.2 類成員默認(rèn)值

Java中類成員可以不賦初始值,編譯器會(huì)自動(dòng)幫你設(shè)置一個(gè)合適的初始值:

class Foo{
     //String類型的默認(rèn)值為null
     String s;
}

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

class Foo{
    //String類型的默認(rèn)值為null
    var s: String = _
}

該語(yǔ)法只適用于類成員,而不適用于局部變量。

1.3 可變參數(shù)

Java聲明可變參數(shù)如下:

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

調(diào)用方法如下:

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

在Java中可以直接將數(shù)組傳給printArgs方法,但是在Scala中,你必須要明確的告訴編譯器,你是想將集合作為一個(gè)獨(dú)立的參數(shù)傳進(jìn)去,還是想將集合的元素傳進(jìn)去。如果是后者則要借助下劃線:

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

1.4 類型通配符

Java的泛型系統(tǒng)有一個(gè)通配符類型,例如List<?>,任意的List<T>類型都是List<?>的子類型,如果我們想編寫一個(gè)可以打印所有List類型元素的方法,可以如下聲明:

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

對(duì)應(yīng)的Scala版本為:

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

2 模式匹配

2.1 默認(rèn)匹配

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

2.2 匹配集合元素

//匹配以0開頭,長(zhǎng)度為三的列表
expr match {
  case List(0, _, _) => println("found it")
  case _ =>
}

//匹配以0開頭,長(zhǎng)度任意的列表
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特有語(yǔ)法

3.1 訪問(wèn)Tuple元素

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

3.2 簡(jiǎn)寫函數(shù)字面量(function literal)

如果函數(shù)的參數(shù)在函數(shù)體內(nèi)只出現(xiàn)一次,則可以使用下劃線代替:

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

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

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

3.3 定義一元操作符

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

-2
//等價(jià)于
2.unary_-

3.4 定義賦值操作符

我們通過(guò)下劃線實(shí)現(xiàn)賦值操作符,從而可以精確地控制賦值過(guò)程:

   class Foo {
      def name = { "foo" }
      def name_=(str: String) {
        println("set name " + str)
   }

    val m = new Foo()
    m.name = "Foo" //等價(jià)于: m.name_=("Foo")

3.5 定義部分應(yīng)用函數(shù)(partially applied function)

我們可以為某個(gè)函數(shù)只提供部分參數(shù)進(jìn)行調(diào)用,返回的結(jié)果是一個(gè)新的函數(shù),即部分應(yīng)用函數(shù)。因?yàn)橹惶峁┝瞬糠謪?shù),所以部分應(yīng)用函數(shù)也因此而得名。

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 將方法轉(zhuǎn)換成函數(shù)

Scala中方法和函數(shù)是兩個(gè)不同的概念,方法無(wú)法作為參數(shù)進(jìn)行傳遞,也無(wú)法賦值給變量,但是函數(shù)是可以的。在Scala中,利用下劃線可以將方法轉(zhuǎn)換成函數(shù):

//將println方法轉(zhuǎn)換成函數(shù),并賦值給p
val p = println _  
//p: (Any) => Unit

4. 小結(jié)

下劃線在大部分的應(yīng)用場(chǎng)景中是以語(yǔ)法糖的形式出現(xiàn)的,可以減少擊鍵次數(shù),并且代碼顯得更加簡(jiǎn)潔。但是對(duì)于不熟悉下劃線的同學(xué)閱讀起來(lái)稍顯困難,希望通過(guò)本文能夠幫你解決這個(gè)的困惑。本文成文倉(cāng)促,如有遺漏,歡迎留言! 轉(zhuǎn)載請(qǐng)注明作者: joymufeng

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容