簡體   English   中英

請解釋使用Option的orNull方法

[英]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 ,將拋出異常)。

如果裝箱值可以為空,則進行隱式參數檢查。

好的用法示例可以在orNull注釋中orNull

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 ,因為NullString的子類型,而類<:<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM