2012-12-08 82 views
3

據我明白Scala中值類只是有包裹原始類型像IntBoolean成另一種類型,而不會引入額外的內存使用情況。所以它們基本上被用作普通類的輕量級替代品。爲什麼值類限制爲AnyVal?

這讓我想起了Haskell的newtype表示法,該表示法還用於將現有類型封裝爲新的類型,因此爲某些數據引入了一個新的接口而不消耗額外的空間(要查看兩種語言的相似性,請考慮例如限制爲一個「構造函數」在HaskellScala中都有一個字段)。

我想知道的是,爲什麼引入由編譯器內聯的新類型的概念並沒有被推廣到Haskell的任何類型的零開銷類型包裝的方法。爲什麼斯卡拉人堅持原始類型(又名AnyVal)?

還是有已​​經在斯卡拉的方式也定義了這種包裝的Scala.AnyRef類型?

+0

'擴展AnyVal'只是用來指示值類,以便不引入新的關鍵字/語法和不會破壞現有的工具。 –

回答

12

他們不限於AnyVal

implicit class RichOptionPair[A,B](val o: Option[(A,B)]) extends AnyVal { 
    def ofold[C](f: (A,B) => C) = o map { case (a,b) => f(a,b) } 
} 

scala> Some("fish",5).ofold(_ * _) 
res0: Option[String] = Some(fishfishfishfishfish) 

值類有各種限制,使它們像輕量級包裝一樣行事,但只能包裝原語不是其中之一。

2

推理記錄爲Scala Improvement Process (SIP)-15。正如Alexey Romanov在他的評論中指出的那樣,這個想法是使用現有的關鍵字來查找表達式,以便編譯器確定這種情況。

爲了使編譯器執行的內聯,若干約束適用,如包裝類是「短暫的」(無場或對象成員,構造體等)。您自動生成內聯類的建議至少有兩個問題:

  1. 編譯器需要遍歷每個類的約束的整個列表。並且由於作爲值類的狀態是隱含的,所以它可以通過在稍後時間向該類添加成員來翻轉,從而打破二進制兼容性。編譯器添加了更多約束,例如,值類成爲禁止繼承的final。所以你必須將這些約束添加到任何想要以這種方式可以被嵌入的類中,然後你只能獲得更多的冗長。

有人可能會認爲其他假設的結構,例如val class Meter(underlying: Double) { ... },但extends AnyVal IMO的優點是不需要語法擴展。所有原始類型都在擴展AnyVal,所以有一個很好的比喻(沒有參考,沒有繼承,有效的表示等)

相關問題