[英]Please explain use of Option's orNull method
Scala的Option類有一個orNull
方法,其簽名如下所示。
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
我被隱含的東西弄糊塗了。 有人請說明如何使用它,理想情況下是一個例子嗎?
scala> Some(1).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
Some(1).orNull
^
scala> (None : Option[Int]).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
(None : Option[Int]).orNull
scala> Some("hi").orNull
res21: java.lang.String = hi
scala> Some(null : String).orNull
res22: String = null
scala> (None : Option[String]).orNull
res23: String = null
解釋隱含的事情:orNull是一種從Some | None成語回到Java的value | null idiom(當然是壞的)的一種方式。 現在只有AnyRef值(類的實例)可以接受空值。
所以我們喜歡的是def orNull[A >: Null] = ....
但是A已經設置好了,我們不想在特征的定義中限制它。 因此,orNull期望證明A是可以為空的類型。 這個證據是一個隱含變量的形式(因此名稱'ev')
<:<[Null, A1]
可以寫成Null <:< A1
,就像這樣,它類似於'Null <:A1'。 <:<在PREDEF以及提供命名隱式值的方法所定義conforms
。
我認為這里並不嚴格要求使用A1,因為orNull使用getOrElse(默認給定的可以是A的超類型)
scala> class Wrapper[A](option: Option[A]) {
| def orNull(implicit ev: Null <:< A): A = if(option.isEmpty) null else option.get
| }
defined class Wrapper
scala> new Wrapper(Some("hi")).orNull
res18: java.lang.String = hi
orNull
目的首先是確保Option
與Java的兼容性。 雖然不鼓勵在Scala中使用null
,但某些接口可能會獲得可為空的引用。
orNull
有一個簡單的實現:
def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null
根據這個, null
將不僅返回boxed nulls( Some(null)
),還返回None
(例如,如果你調用None.get
,將拋出異常)。
如果裝箱值可以為空,則進行隱式參數檢查。
val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)
請記住,在Scala中,原始類型和引用類型是統一的 - 但只有引用類型可以為空。 隱式只允許編譯器確認A1是引用類型。
為了理解它有用的原因, IttayD提供了一個很好的解釋 :
所以我們想要的是def
orNull[A >: Null] = .....
但是A已經設置好了,我們不想在特征的定義中限制它。 因此,orNull期望證明A是可以為空的類型。 這個證據是一個隱含變量的形式(因此名稱'ev')
總之,當您希望在具有更多特定約束(例如Null <: A <: Any
)的泛型類(例如, Option
)上具有方法(例如, orNull
)時,類型約束非常有用,而不是類本身(例如A <: Any
) 。
這是另一個“功能”,它不是內置於語言中,而是由於隱式參數和類型參數的方差注釋而免費提供。 要理解這一點,請查看<:<
的定義:
// from Predef
sealed abstract class <:<[-From, +To] extends (From => To)
implicit def conforms[A]: A <:< A = new (A <:< A) {def apply(x: A) = x}
對於
scala> Some(1).orNull
<console>:10: error: could not find implicit value for parameter ev: <:<[Null,Int]
Some(1).orNull
編譯器查找類型<:<[Null, Int]
的隱式值,並找到方法def conforms[A]: A <:< A
。 所以必須有一個A
<:<[A, A]
符合<:<[Null, Int]
。 這沒有A
,因此編譯器會抱怨缺少隱含值。
但是,對於
scala> Some("hi").orNull
res21: java.lang.String = hi
我們很幸運。 現在,編譯器試圖找到一個A
為其<:<[A, A]
符合<:<[Null, String]
。 這適用於A = String
,因為Null
是String
的子類型,而類<:<
的From
類型參數定義為逆變量。
如上所述,考慮類型約束的最直觀方式是將其讀取為類型綁定(即將其讀取為Null <:Int)。 Null
不符合Int
並且<:<[Null,Int]沒有隱含值。 另一方面, Null
確實符合String
,編譯器將找到隱含參數。
順便說一下,這是另一個相關的答案 。
Re:'how'是如何使用的 - 我們發現這個有用的地方是處理java api映射,其中null
是常見的,例如在jdbc預處理語句中可以為nullable sql列。 Option
al內部模型字段可以映射:
stmt.setDate("field", myModel.myDateField.orNull)
而不是更冗長:
stmt.setDate("field", myModel.myDateField.getOrElse(null))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.