1. 程式人生 > >Scala基礎:閉包、柯里化、隱式轉換和隱式引數

Scala基礎:閉包、柯里化、隱式轉換和隱式引數

閉包,和js中的閉包一樣,返回值依賴於宣告在函式外部的一個或多個變數,那麼這個函式就是閉包函式。

    val i: Int = 20
    //函式func的方法體中使用了在func外部定義的變數 那func就是個閉包函式
    val func = (x: Int) => x + i

 

柯里化(Currying)指的是把原來接受多個引數的函式變換成接受一個引數的函式過程,並且返回接受餘下的引數且返回結果為一個新函式的技術。柯里化並不是scala特有的,js中也有。

package com.zy.scala

object CurryingDemo {
  def main(args: Array[String]): Unit 
= { //原本的方法 def m(x: Int, y: Int) = x + y //第一種柯里化 def first(x: Int) = (y: Int) => x + y val second = first(1) val result: Int = second(2) println(result) //第二種柯里化 def curriedSum(x: Int)(y: Int) = x + y val sum: Int = curriedSum(1)(2) println(sum) } }

 

Scala 提供的隱式轉換和隱式引數功能,是非常有特色的功能。是 Java 等程式語言所沒有的功能。它可以允許你手動指定,將某種型別的物件轉換成其他型別的物件或者是給一個類增加方法。通過這些功能,
可以實現非常強大、特殊的功能。 Scala 的隱式轉換,其實最核心的就是定義隱式轉換方法,即 implicit conversion function。定義的隱式轉換方法,只要在編寫的程式內引入,就會被Scala 自動使用。Scala 會根據隱式轉換方法的簽名,
在程式中使用到隱式轉換方法接收的引數型別定義的物件時,會自動將其傳入隱式轉換方法,轉換為另外一種型別的物件並返回。這就是“隱式轉換”。其中所有的隱式值和隱式方法必須放到 object 中。 然而使用 Scala 的隱式轉換是有一定的限制的,總結如下:   implicit 關鍵字只能用來修飾方法、變數(引數)。   隱式轉換的方法在當前範圍內才有效。如果隱式轉換不在當前範圍內定義(比如定義在另一個類中或包含在某個物件中),那麼必須通過
import 語句將其導。 所謂的隱式引數,指的是在函式或者方法中,定義一個用 implicit 修飾的引數,此時 Scala 會嘗試找到一個指定型別的,用 implicit 修飾的引數,即隱式值,並注入引數。 Scala 會在兩個範圍內查詢:   當前作用域內可見的 val 或 var 定義的隱式變數;   一種是隱式引數型別的伴生物件內的隱式值;

 

隱式引數案例

package com.zy.scala

object Company {
  //在 object 中定義隱式值 注意:同一型別的隱式值只允許出現一次,否則會報錯
  implicit val aaa = "zhangsan"
  implicit val bbb = 10000.00
}

class Boss {
  //注意引數匹配的型別 它需要的是 String 型別的隱式值
  def callName()(implicit name: String): String = {
    name + " is coming !"
  }

  //定義一個用 implicit 修飾的引數
  //注意引數匹配的型別 它需要的是 Double 型別的隱式值
  def getMoney()(implicit money: Double): String = {
    " 當月薪水:" + money
  }
}

object Boss extends App {
  //使用 import 匯入定義好的隱式值,注意:必須先載入否則會報錯
  import Company._

  val boss = new Boss
  println(boss.callName() + boss.getMoney())
}

 

隱式轉換

package com.zy.scala

import java.io.File
import scala.io.Source

object MyPredef {
  //定義隱式轉換方法
  implicit def file2RichFile(file: File) = new RichFile(file)
}

class RichFile(val f: File) {
  def read() = Source.fromFile(f).mkString
}

object RichFile {
  def main(args: Array[String]) {
    val f = new File("E://words.txt")
    //使用 import 匯入隱式轉換方法
    import MyPredef._
    //通過隱式轉換,讓 File 類具備了 RichFile 類中的方法
    val content = f.read()
    println(content)
  }
}
package com.zy.scala

class Man(val name: String)

class SuperMan(val name: String) {
  def heat = print("超人打怪獸")
}

object SuperMan {
  //隱式轉換方法
  implicit def man2SuperMan(man: Man) = new SuperMan(man.name)

  def main(args: Array[String]) {
    val hero = new Man("hero")
    //Man 具備了 SuperMan 的方法
    hero.heat
  }
}
package com.zy.scala

class A(c: C) {
  def readBook(): Unit = {
    println("A 說:好書好書...")
  }
}

class B(c: C) {
  def readBook(): Unit = {
    println("B 說:看不懂...")
  }

  def writeBook(): Unit = {
    println("B 說:不會寫...")
  }
}

class C

object AB {
  //建立一個類的 2 個類的隱式轉換
  implicit def C2A(c: C) = new A(c)

  implicit def C2B(c: C) = new B(c)
}

object B {
  def main(args: Array[String]) {
    //導包
    //1. import AB._ 會將 AB 類下的所有隱式轉換導進來
    //2. import AB._C2A 只匯入 C 類到 A 類的的隱式轉換方法
    //3. import AB._C2B 只匯入 C 類到 B 類的的隱式轉換方法
    import AB._
    val c = new C
    //由於 A 類與 B 類中都有 readBook(),只能匯入其中一個,否則呼叫共同方法時程式碼報錯
    //c.readBook()
    //C 類可以執行 B 類中的 writeBook()
    c.writeBook()
  }
}