2013-02-18 20 views
43

說我寫的擴展方法隱含類應該總是擴展AnyVal嗎?

implicit class EnhancedFoo(foo: Foo) { 
    def bar() { /* ... */ } 
} 

如果你總是在類中包含defininition extends AnyVal?在什麼情況下你不想讓一個隱式類成爲一個值類?

回答

38

讓我們來看看limitations listed for value classes並認爲當他們隱類可能不適合:

  1. 「必須只可以精確到一個公共的,VAL參數,其類型不是值類的主要構造。 「所以,如果你是包裝類本身就是一個值類,你不能使用implicit class作爲一個包裝,但你可以這樣做:

    // wrapped class 
    class Meters(val value: Int) extends AnyVal { ... } 
    
    // wrapper 
    class RichMeters(val value: Int) extends AnyVal { ... } 
    
    object RichMeters { 
        implicit def wrap(m: Meter) = new RichMeter(m.value) 
    } 
    

    如果包裝有隱含參數,以及,你可以嘗試將它們移動到方法聲明。即而不是

    implicit class RichFoo[T](foo: Foo[T])(implicit ord: Ordering[T]) { 
        def bar(otherFoo: Foo[T]) = // something using ord 
    } 
    

    你有

    implicit class RichFoo[T](foo: Foo[T]) extends AnyVal { 
        def bar(otherFoo: Foo[T])(implicit ord: Ordering[T]) = // something using ord 
    } 
    
  2. 「可能沒有專門的類型參數。」你可能希望封裝器在封裝一個本身具有特定類型參數的類時專用。

  3. 「可能沒有嵌套的或局部的類,特徵或對象」再一次,這對於實現包裝器很有用。
  4. 「可能未定義equalshashCode方法」。無關緊要,因爲隱式類也不應該有equals/hashCode
  5. 「必須是頂級類或靜態可訪問對象的成員」這也是您通常定義隱式類的位置,但不是必需的。
  6. 「只能顯示成員,特別是不能有懶惰的vals,vars或vals作爲成員。」隱式類可以包含所有這些,但我無法想象用於varlazy val的合理用例。 「
  7. 」不能被其他課程擴展。「同樣,隱式類可以擴展,但可能沒有什麼好的理由。

另外,讓隱式類成爲一個值類可能會改變一些使用反射的代碼行爲,但反射通常不會看到隱式類。

如果你的隱式類確實滿足所有這些限制,我想不出一個理由不把它作爲一個值類。

+0

fwiw,下面是'隱式類'內的'lazy val'的用例:https://gist.github。com/SethTisue/8977033。幸運的是,有一個簡單的解決方法(也在要點中顯示)。 – 2014-02-13 15:28:39

+1

「我想不出一個理由不讓它成爲價值課。」 - 因爲它分散注意力,但沒有任何好處。在我的測試中,我一直無法重現「擴展AnyVal」隱式類的所謂記憶好處。你有沒有提到好處? – Rich 2015-06-29 13:24:23

+0

該文檔仍然推薦它,但我無法在測試中測量任何好處。 http://docs.scala-lang.org/overviews/core/value-classes.html – Rich 2015-06-29 13:49:36

2

我覺得你很困惑Value ClassesImplicit Classes。在爲增強定義隱式類時,您幾乎不會擴展任何內容,而值類必須擴展爲AnyVal

+11

我可以把這個問題改爲「應該隱式類總是值類?」。如果它消除了實例創建的開銷,爲什麼你不希望隱式類是一個值類? – 2013-02-18 04:44:10

+2

值類有很多限制。如果它們合適,當然可以使用它們進行增強。 – 2013-02-18 04:48:28

相關問題