Scala的Option類有一個orNull
方法,其簽名如下所示。請解釋使用Option的orNull方法
orNull [A1 >: A](implicit ev : <:<[Null, A1]) : A1
我對隱含的東西感到困惑。請有人解釋一下如何使用它,理想情況下用一個例子?
Scala的Option類有一個orNull
方法,其簽名如下所示。請解釋使用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是獲得來自一些回來的路|無成語Java的價值|空成語(這是當然的,壞)。現在只有AnyRef值(類的實例)可以接受空值。
所以我們會喜歡的是def orNull[A >: Null] = ....
。但是A已經設定好了,我們不想限制它在特質的定義中。因此,或者Null期望證明A是可爲空的類型。這個證據的形式是一個隱含的變量(因此名字爲'ev')
<:<[Null, A1]
可以寫成Null <:< A1
看到它是這樣的,它類似於'空'<: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
看到這樣的事情,實際上很難不愛Scala。 – Madoc 2010-12-17 06:15:29
圖書館編寫者走了很長的路要把所有東西都模塊化,並且工作得很好;缺點是簽名對於局外人來說通常看起來很奇怪,而且錯誤信息是無法理解的。一個好的提示可能是忽略它,只是閱讀文檔。 :-) – 2010-12-17 08:42:20
orNull
目的是在保證兼容性首先是用Java編寫的Option
。儘管在Scala中不鼓勵使用null
,但某些接口可能會獲得可空的引用。
orNull
有一個簡單的實現:
def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null
據此,null
將被退回不僅爲盒裝空值(Some(null)
),同時也爲None
(例如,如果你調用None.get
,將引發異常)。
隱式參數檢查,如果裝箱值可以爲空。
良好的使用示例可以直接在comments to orNull
發現:
val initialText: Option[String] = getInitialText
val textField = new JComponent(initialText.orNull,20)
只是爲了使其更加明確:這僅適用於引用類型(AnyRef的子類型),但不適用於值類型(AnyVal的子類型),因爲它們沒有空值。 – 2010-12-17 08:20:39
那麼,如果getInitialText代替getInitialText,返回Long?假設你想把這個很長的數字傳遞給Java,或者如果它沒有被定義,則爲null。 – David 2010-12-17 19:37:52
然後,您需要使用類型歸屬,顯式指定'java.lang.Long'而不是'scala.Long':'val initialText:Option [java.lang.Long] = getInitialLong' – 2010-12-17 20:56:27
要理解爲什麼它是有用的,IttayD provided a nice explanation:
那麼,我們所希望的是高清
orNull[A >: Null] = .....
但A是 已經設置,我們不想 限制它在 特質的定義。因此,orNull期望證明A是可爲空的類型。 這方面的證據是在 隱變量(故名 「EV」)
概括的形式,當你想有方法(如orNull
)在泛型類(如Option
類型約束是有用的)與更具體的約束(例如Null <: A <: Any
)相比,在類本身(例如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
類型參數被定義爲逆變)。如上所述,考慮類型約束最直觀的方式是將其讀取爲類型綁定(即將其讀取爲空值<:Int)。 Null
不符合Int
,並且<沒有隱式值:< [Null,Int]。另一方面,Null
確實符合String
,編譯器將查找隱式參數。
順便說一下,這裏是另一個related answer。
回覆:這是如何使用的 - 我們發現這個有用的一個地方是在處理java API映射時,其中null
很常見,例如,在jdbc準備好的語句中爲可空的sql列。所述Option
人內部模型字段可以被映射:
stmt.setDate("field", myModel.myDateField.orNull)
相反的更詳細的:
stmt.setDate("field", myModel.myDateField.getOrElse(null))
唉,源代碼使用'空<:
2010-12-17 10:49:23