雜記四:scala 柯理化和隱式轉換

Cape_sir發表於2021-01-04

1、柯理化

柯里化(Currying)指的是將原來接受兩個引數的函式變成新的接受一個引數的函式的過程。新的函式返回一個以原有第二個引數為引數的函式。

例項
首先我們定義一個函式:

def add(x:Int,y:Int)=x+y

那麼我們應用的時候,應該是這樣用:add(1,2)
現在我們把這個函式變一下形:

def add(x:Int)(y:Int) = x + y

那麼我們應用的時候,應該是這樣用:add(1)(2),最後結果都一樣是3,這種方式(過程)就叫柯里化。

實現過程
add(1)(2) 實際上是依次呼叫兩個普通函式(非柯里化函式),第一次呼叫使用一個引數 x,返回一個函式型別的值,第二次使用引數y呼叫這個函式型別的值。
實質上最先演變成這樣一個方法:

def add(x:Int)=(y:Int)=>x+y

那麼這個函式是什麼意思呢? 接收一個x為引數,返回一個匿名函式,該匿名函式的定義是:接收一個Int型引數y,函式體為x+y。現在我們來對這個方法進行呼叫。

val result = add(1) 

返回一個result,那result的值應該是一個匿名函式:(y:Int)=>1+y
所以為了得到結果,我們繼續呼叫result。

val sum = result(2)

最後列印出來的結果就是3。

完整例項
下面是一個完整例項:

object Test {
   def main(args: Array[String]) {
      val str1:String = "Hello, "
      val str2:String = "Scala!"
      println( "str1 + str2 = " +  strcat(str1)(str2) )
   }

   def strcat(s1: String)(s2: String) = {
      s1 + s2
   }
}

執行以上程式碼,輸出結果為:

$ scalac Test.scala
$ scala Test
str1 + str2 = Hello, Scala!

2、隱式轉換

我們需要某個類中的一個方法,但是這個類沒有提供這樣的一個方法,所以我們需要隱式轉換,轉換成提供了這個方法的類,然後再呼叫這個方法。

定義在公共物件中的隱式轉換:

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

//這裡的RichFile相當於File的增強類 需要將被增強的類作為引數傳入構造器中
class RichFile(val file: File) {
  def read = {
      Source.fromFile(file.getPath).mkString
  }
}
 
//implicit是隱式轉換的關鍵字 這裡定義一個隱式轉換函式把當前型別轉換成增強的型別(函式名稱一般是source2target)
object Context {
    //File --> RichFile
    implicit def file2RichFile(file: File) = new RichFile(file)
}
 
object Hello_Implicit_Conversions {
    def main(args: Array[String]): Unit = {
        //匯入隱式轉換
        import Context.file2RichFile
        //File類本身沒有read方法 通過隱式轉換完成
        //這裡的read方法是RichFile類中的方法  需要通過隱式轉換File --> RichFile
        println(new File("E:\\projectTest\\1.txt").read)
      
    }
}

定義在原型別的伴生物件中:

class Person(val name: String)
// 在伴生物件中定義隱式轉換函式
object Person{
  implicit def person2Thor(p: Person): Thor = new Thor(p.name)
}
class Thor(val name: String) {
  def hammer(): Unit = {
    println(name + "舉起雷神之錘")
  }
}
// 使用示例
object ScalaApp extends App {
  new Person("普通人").hammer()
}

隱式引數

object Context_Implicits {
    implicit val default: String = "Java"
}

object Param {
    //函式中用implicit關鍵字 定義隱式引數
    def print(context: String)(implicit language: String){
        println(language+":"+context)
    }
}

object Implicit_Parameters {
    def main(args: Array[String]): Unit = {
        //隱式引數正常是可以傳值的,和普通函式傳值一樣  但是也可以不傳值,因為有預設值(預設配置)
        Param.print("Spark")("Scala")   //Scala:Spark
        
        import Context_Implicits._
        //隱式引數沒有傳值,編譯器會在全域性範圍內搜尋 有沒有implicit String型別的隱式值 並傳入
        Param.print("Hadoop")          //Java:Hadoop
    }
}

相關文章