簡單的答案是否定的,類型系統不能告訴你,如果一個類有一個默認的構造函數。請記住,案例類通常不具有默認構造函數,因爲不建議使用無參數的案例類。默認構造函數的概念對於不可變對象不是很有用。 AFAIK沒有理由不原則上(Scala確實支持結構類型,其中類型必須具有特定名稱的方法),但它需要語言更改。你可以在運行時檢查反射,但這不是你想要的。
但是,您可以使用類型類模式強制默認值是在範圍之內。這在概念上與添加OP中建議的額外默認論證非常相似,但使用隱含來隱藏它們。它在收藏庫中大量使用。 missingfaktor的回答使用scalaz.Zero
就是這方面的一個特例,但是在vanilla Scala中這樣做並不容易,而且對於一些任意的默認值,這不一定是某種零。
case class Default[T](default: T)
case class Foo(value: String)
case class Bar(value: Int)
implicit val fooDefault = Default(Foo("I'm a default Foo")) // note 1
現在讓我們來看一個例子用法:
def firstItem[T](lst: List[T]) (implicit ev: Default[T]) = // note 2
if (lst.isEmpty) ev.default else lst.head
val fooList = List(Foo("cogito"), Foo("ergo"), Foo("sum"))
val emptyFooList = List[Foo]()
val barList = List(Bar(101), Bar(102))
val emptyBarList = List[Bar]()
firstItem(fooList) // Foo("cogito")
firstItem(emptyFooList) // Foo("I'm a default Foo")
firstItem(barList) // ** error: missing implicit **
所以我們看到,這個編譯與List[Foo]
,但List[Bar]
是不能接受的,因爲沒有隱含Default[Bar]
(注3)。
注1:此隱含可以在object Foo
被定義 - 這將確保它的範圍,如果你導入類的其他地方。但它不一定是:你也可以爲任意類定義類似的暗示,Int
,String
,不管(嘗試它)。注意2:這相當於加糖版本def firstItem[T: Default](lst: List[T]) =
...,你在那裏召喚ev
與implicitly[Default[T]]
。拿你的選擇。
注3:我們可以把它簡單地提供一個工作:
firstItem(barList)(Default(Bar(42))) // Bar(101)
firstItem(emptyBarList)(Default(Bar(42))) // Bar(42)
注:'F'是一種方法,而不是一個函數。函數是用'=>'創建的(這基本上就是用於匿名擴展'FunctionN'特性之一和重載'apply'的語法糖),'def'定義了方法。 – 2012-02-14 16:07:17
同意,謝謝澄清。 – folone 2012-02-15 08:26:50