深入理解隱式轉換

2021-09-17 04:43:33 字數 4113 閱讀 2604

摘要:

通過隱式轉換,程式設計師可以在編寫scala程式時故意漏掉一些資訊,讓編譯器去嘗試在編譯期間自動推導出這些資訊來,這種特性可以極大的減少**量,忽略那些冗長,過於細節的**。

使用方式:

1.將方法或變數標記為implicit

2.將方法的引數列表標記為implicit

3.將類標記為implicit

scala支援兩種形式的隱式轉換:

隱式值:用於給方法提供引數

隱式檢視:用於型別間轉換或使針對某型別的方法能呼叫成功

隱式值:

例1:宣告person方法。其引數為name,型別string

scala> def person(implicit name : string) = name   //name為隱式引數

person: (implicit name: string)string

直接呼叫person方法

scala> person

:9: error: could not find implicit value for parameter name: string

person

^

報錯!編譯器說無法為引數name找到乙個隱式值

定義乙個隱式值後再呼叫person方法

scala> implicit val p = "mobin"   //p被稱為隱式值

p: string = mobin

scala> person

res1: string = mobin

因為將p變數標記為implicit,所以編譯器會在方法省略隱式引數的情況下去搜尋作用域內的隱式值作為缺少引數。

但是如果此時你又在repl中定義乙個隱式變數,再次呼叫方法時就會報錯

scala> implicit val p1 = "mobin1"

p1: string = mobin1

scala> person

:11: error: ambiguous implicit values:

both value p of type => string

and value p1 of type => string

match expected type string

person

^

匹配失敗,所以隱式轉換必須滿足無歧義規則,在宣告隱式引數的型別是最好使用特別的或自定義的資料型別,不要使用int,string這些常用型別,避免碰巧匹配

隱式檢視

隱式轉換為目標型別:把一種型別自動轉換到另一種型別

例2:將整數轉換成字串型別:

scala> def foo(msg : string) = println(msg)

foo: (msg: string)unit

scala> foo(10)

:11: error: type mismatch;

found : int(10)

required: string

foo(10)

^

顯然不能轉換成功,解決辦法就是定義乙個轉換函式給編譯器將int自動轉換成string

scala> implicit def inttostring(x : int) = x.tostring

inttostring: (x: int)string

scala> foo(10)

10

隱式轉換呼叫類中本不存在的方法例3:通過隱式轉換,使物件能呼叫類中本不存在的方法

class swingtype

object swimming

class aminaltype

import com.mobin.scala.scalaimplicit.swimming._

val rabbit = new aminaltype

rabbit.wantlearned("breaststroke") //蛙泳

}

編譯器在rabbit物件呼叫時發現物件上並沒有wantlearning方法,此時編譯器就會在作用域範圍內查詢能使其編譯通過的隱式檢視,找到learningtype方法後,編譯器通過隱式轉換將物件轉換成具有這個方法的物件,之後呼叫wantlearning方法

可以將隱式轉換函式定義在伴生物件中,在使用時匯入隱式檢視到作用域中即可(如例4的learningtype函式)

還可以將隱式轉換函式定義在兇物件中,同樣在使用時匯入作用域即可,如例4

例4:

class swingtype

package swimmingpage

}class aminaltype

import com.mobin.scala.scalaimplicit.swimmingpage.swimming._ //使用時顯示的匯入

val rabbit = new aminaltype

rabbit.wantlearned("breaststroke") //蛙泳

}

像inttostring,learningtype這類的方法就是隱式檢視,通常為int => string的檢視,定義的格式如下:

implicit def  originaltotarget (: originaltype) : targettype

其通常用在於以兩種場合中:

1.如果表示式不符合編譯器要求的型別,編譯器就會在作用域範圍內查詢能夠使之符合要求的隱式檢視。如例2,當要傳乙個整數型別給要求是字串型別引數的方法時,在作用域裡就必須存在int => string的隱式檢視

2.給定乙個選擇e.t,如果e的型別裡並沒有成員t,則編譯器會查詢能應用到e型別並且返回型別包含成員t的隱式檢視。如例3

隱式類:

在scala2.10後提供了隱式類,可以使用implicit宣告類,但是需要注意以下幾點:

1.其所帶的構造引數有且只能有乙個

2.隱式類必須被定義在類,伴生物件和包物件裡

3.隱式類不能是case class(case class在定義會自動生成伴生物件與2矛盾)

4.作用域內不能有與之相同名稱的標示符

例5:

object stringutils 

} import com.mobin.scala.implicitpackage.stringutils._

println("mobin".increment)

}

編譯器在mobin物件呼叫increment時發現物件上並沒有increment方法,此時編譯器就會在作用域範圍內搜尋隱式實體,發現有符合的隱式類可以用來轉換成帶有increment方法的stringimprovement類,最終呼叫increment方法。

隱式轉換的時機:

1.當方法中的引數的型別與目標型別不一致時

2.當物件呼叫類中不存在的方法或成員時,編譯器會自動將物件進行隱式轉換

隱式解析機制

即編譯器是如何查詢到缺失資訊的,解析具有以下兩種規則:

1.首先會在當前**作用域下查詢隱式實體(隱式方法  隱式類 隱式物件)

2.如果第一條規則查詢隱式實體失敗,會繼續在隱式引數的型別的作用域裡查詢

(1)如果t被定義為t with a with b with c,那麼a,b,c都是t的部分,在t的隱式解析過程中,它們的伴生物件都會被搜尋

(2)如果t是引數化型別,那麼型別引數和與型別引數相關聯的部分都算作t的部分,比如list[string]的隱式搜尋會搜尋list的

伴生物件和string的伴生物件

(3) 如果t是乙個單例型別p.t,即t是屬於某個p物件內,那麼這個p物件也會被搜尋

(4) 如果t是個型別注入s#t,那麼s和t都會被搜尋

隱式轉換的前提:

1.不存在二義性(如例1)

2.隱式操作不能巢狀使用(如 convert1(covert2(x)))+y

深入理解C語言型別轉換

c語言型別轉換分為兩種 也許你曾經遇到過乙個負數經過型別轉換後可能變成乙個很大的整數之類的現象,卻不知道實質上是因為什麼,只是淺顯地了解到型別轉換會向著更大精度的方向轉化。尤其是對於計算機基礎知識不紮實或者很多半路出家 比如我 的人來說不是很了解背後的原因。希望下面的解釋能夠解決這個疑惑。本文以c語...

深入理解分布式事務

碼農網 吳極心 當資料庫單錶一年產生的資料超過1000w,那麼就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以後有空詳細說,簡單的說就是原來的乙個資料庫變成了多個資料庫。這時候,如果乙個操作既訪問01庫,又訪問02庫,而且要保證資料的一致性,那麼就要用到分布式事務。所謂的soa化,就是業務的服務...

深入理解分布式事務

當資料庫單錶一年產生的資料超過1000w,那麼就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以後有空詳細說,簡單的說就是原來的乙個資料庫變成了多個資料庫。這時候,如果乙個操作既訪問01庫,又訪問02庫,而且要保證資料的一致性,那麼就要用到分布式事務。所謂的soa化,就是業務的服務化。比如原來單機...