简单的答案是否定的,类型系统不能告诉你,如果一个类有一个默认的构造函数。请记住,案例类通常不具有默认构造函数,因为不建议使用无参数的案例类。默认构造函数的概念对于不可变对象不是很有用。 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