Scala入門到放棄——異常處理和隱式轉換(九)

十二、異常處理

異常

  • Scala 的異常處理和其它語言比如 Java 類似。
  • Scala 的方法可以通過拋出異常的方法的方式來終止相關代碼的運行,不必通過返回值。
package exception

import java.io.IOException


/**
  * scala異常分類和java一樣的
  * Throwable
  *    |- Error
  *    |- Exception
  *    |- 未檢查異常
  *    |- 已檢查異常
  *
  * 異常處理的方式:
  *    - 消極處理: throw 異常類 沒有throws
  *    - 積極處理: try{...}catch(){...}finally{...}
  */
object ExceptionDemo {
  def main(args: Array[String]): Unit = {
    try {
      println("start")
      // throw new RuntimeException("程序終止!!") // Exception in thread "main" java.lang.RuntimeException: 程序終止!!
      throw new IOException
      println("end")
    } catch {
      // 模式匹配
      case e1: RuntimeException => println("runtime exception")
      case e2: Exception => println("exception")
      case _ => println("xxxx") // 如果以上聲明的兩種異常不匹配,則進入最後一個
    } finally {
      println("釋放資源")
    }
  }
}

十三、隱式轉換

隱式轉換函數(implicit conversion function)指的是以implicit關鍵字聲明的帶有單個參數的函數。這樣的函數將被自動應用,將值從一種類型轉換爲另一種類型。隱式轉換函數叫什麼名字是無所謂的,因爲通常不會由用戶手動調用,而是由Scala進行調用。但是如果要使用隱式轉換,則需要對隱式轉換函數進行導入(import)。因此通常建議將隱式轉換函數的名稱命名爲“one2one”的形式。

常用使用方式:

  • 隱式值
  • 隱式參數
  • 參數的隱式轉換
  • 隱式類

Scala會考慮如下位置的隱式轉換函數:

  • 位於源或目標類型的伴生對象中的隱式函數
  • 位於當前作用域可以以單個標識符指代的隱式函數

隱式轉換在如下三種不同情況下會被考慮:

  • 當表達式類型與預期類型不同時
  • 當對象訪問一個不存在成員時
  • 當對象調用某個方法,而這個方法的參數聲明與傳入參數不匹配時

有三種情況編譯器不會嘗試使用隱式轉換

  • 如果代碼能夠在不使用隱式轉換的前提下通過編譯,則不會使用隱式轉換
  • 編譯器不會嘗試同時執行多個轉換
  • 存在二義性的轉換是錯誤

隱式值

/**
  * implicit 隱式值
  */
object ImplicitValue {

  // 隱式值聲明 對象內部或者作用域
  implicit val name: String = "Hello"

  // implicit val address:String = "bj"  // error

  implicit val sex: Boolean = false // ok


  def main(args: Array[String]): Unit = {
    // 使用隱式值
    val newValue = implicitly[String]
    val newValue2 = implicitly[Boolean]
    println(newValue)
    println(newValue2)
  }
}

隱式參數(傳值)

方法或者函數的參數,在聲明時有implicit。要求參數之中只能有一個implicit類型匹配。

package implicits

/**
  * 隱式參數
  *
  */
object ImplicitParams {
  // 聲明隱式值 缺省值
  implicit var num: Int = 10

  def main(args: Array[String]): Unit = {
    println(sum(10))
    println(sum(10)(20))
  }

  def sum(x: Int)(implicit y: Int): Int = { // y是隱式參數 適用於柯里化函數
    x + y
  }

  //  def sum2(x: Int,implicit y: Int): Int = { // 不可以 普通函數是無法使用隱式參數
  //    x + y
  //  }

  implicit val str: String = "Hello"

  //  def sum3(x: Int)(implicit y: Int)(implicit z: String): Int = { // 不可以 隱式參數只能在柯里化函數中出現一次
  //
  //  }
}

參數隱式轉換

class Student(var name: String)

object Implicit1 {
  def main(args: Array[String]): Unit = {
    sayHi("zs")  // 傳入的類型和方法的參數類型 不匹配,觸發隱式轉換 str--->student
  }

  implicit def strToStudent(str: String): Student = {  
    new Student(str)
  }

  def sayHi(student: Student): Unit = {
    println("Hello:" + student.name)
  }
}

隱式轉換增強現有類型

object Implicit2 {
  implicit def manToSuperMan(man: Man): SuperMan = new SuperMan(man.name)
  
  def main(args: Array[String]): Unit = {
    val man = new Man("小張")
    man.fly()
  }
}

class Man(val name: String)

class SuperMan(val name: String) {

  def fly(): Unit = {
    println("超人會飛...")
  }
}

隱式類

在上面的例子中爲了讓人也能夠飛,需要在SuperMan中定義fly方法,再寫一個隱式轉換函數,將Man隱式轉換爲SuperMan。這種寫法過於囉嗦,可以使用隱式類實現等價功能

class Man2(val name: String)

object Implicit5 {
  def main(args: Array[String]): Unit = {
    implicit class SuperMan2(man: Man2) {
      var name: String = _
      def fly = {
        this.name = man.name
        println(s"$name ---> 超人會飛")
      }
    }
    val man = new Man2("zs")
    man.fly
  }
}

隱式類就是在類定義前加一個implicit關鍵字,這表示它的構造函數是一個隱式轉換函數,能夠將參數的類型轉換成自己的類型,在這裏就是構造函數SuperMan2(man: Man2)定義了Man2SuperMan2的隱式轉換。

注意:使用隱式類時需要注意以下限制條件

  • 只能在別的trait/類/對象內部定義
  • 構造函數只能攜帶一個非隱式參數
  • implict關鍵字不能用於case類

引入隱式轉換

隱式值

  • 定義在伴生對象或者作用域
  • 引用其它對象的 import 對象._
package implicits

object Implicit3 {
  // 伴生類的類體
  implicit var x: Int = 0

  def main(args: Array[String]): Unit = {
    // 伴生類的函數體
    implicit var str: String = "Hi"

    import AA._ // 類似於java的靜態導入

    var ll: Long = implicitly[Long]
    println(ll)
  }
}

object AA {
  // 其它對象中定義了一個隱式值
  implicit var l: Long = 1000L
}

隱式參數

  • 定義在伴生對象或者作用域或import
package implicits
object Implicit4 {

  def main(args: Array[String]): Unit = {
    implicit var x: Int = 10

    //    def sum(x: Int)(implicit y: Int): Int = {
    //      x + y
    //    }
    import BB._
    println(sum(10))
  }

  // 類體
  //  def sum(x: Int)(implicit y: Int): Int = {
  //    x + y
  //  }
}

object BB {
  def sum(x: Int)(implicit y: Int): Int = {
    x + y
  }
}

參數隱式轉換

  • 定義在伴生對象或者作用域
  • 其它類,需要import
package implicits

import CC._

object Implicit5 {
  def main(args: Array[String]): Unit = {
    sayHi("ls")

    //    implicit def str2Student(str: String): Student2 = {
    //      new Student2(str)
    //    }
  }

  def sayHi(student: Student2): Unit = {
    println(student.name)
  }

  //  implicit def str2Student(str: String): Student2 = {
  //    new Student2(str)
  //  }
}

class Student2(var name: String)

object CC {
  implicit def str2Student(str: String): Student2 = {
    new Student2(str)
  }
}

隱式類

package implicits

import DD._

/**
  *
  * 隱式類
  */
object Implicit2 {
  def main(args: Array[String]): Unit = {
    val man2 = new Man2("zs")
    man2.fly
    println(man2.name)

    // 隱式類 接受Man2對象  構建SuperMan2獨享
    //    implicit class SuperMan2(man2: Man2) {
    //      var name: String = _
    //
    //      def fly = {
    //        // this.name = man2.name
    //        println("飛翔...")
    //      }
    //    }
  }
}

class Man2(var name: String)

//implicit class SuperMan2(man2: Man2) {  //error
//  var name: String = _
//
//  def fly = {
//    // this.name = man2.name
//    println("飛翔...")
//  }
//}

object DD {

  implicit class SuperMan2(man2: Man2) { //error
    var name: String = _
    def fly = {
      // this.name = man2.name
      println("飛翔...")
    }
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章