使用多种语言可以轻松完成,但Scala不是这样:
定义原型'超级',这样'超级'的所有实现都必须定义构造函数'create()'。
我发现这个约束非常重要,能够在运行时识别出很多问题。但是,此功能仅在Java中部分强制执行(通过定义始终抛出错误的“抽象”静态方法)并在Scala中完全丢失(伴随对象与类完全分离,无法在原型中强制执行)。
是否有允许我这样做的宏或工具?
更新抱歉,我的问题是缺少上下文和示例。这是scala中的正式用例:
在项目A中,我们定义了一个可以由所有子项目扩展的接口:
trait AbstractFoo {}
此接口应始终具有默认的0参数构建器/构造函数,因此项目A可以按需初始化它,但是,项目A不知道每个构造函数的实现:
object AbstractFoo {
def default[T <: AbstractFoo: ClassTag](): T
}
所以问题变成了:如何严格定义AbstractFoo,这样对于A的所有子项目,AbstractFoo的任何实现:
case class Foo(...) extends AbstractFoo
必须满足:
'Foo'必须定义0参数构建器/构造函数(可能在其伴随对象中)
调用AbstractFoo.defaultFoo可以调用这个0参数构建器/构造函数
应该注意的是,在另一种情况下,存在一种解决方案,即将每个伴随对象定义为隐式类型:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
}
object AbstractFoo {
implicit object Foo extends FooBuilder[Foo] {
def default() = {...}
}
def default[T <: AbstractFoo: FooBuilder](): T = {
implicitly[FooBuilder[T]].default
}
}
这样如果隐式对象未定义,编译器将给出一个隐含的未找到错误(我的代码片段可能有一些语法错误,这个想法来自http://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala)
不幸的是,它并不总是方便,因为A的这个子项目通常是项目A所不知道的。但是默认的隐式构建器不能重新定义,这使得default()的每次调用都更加卷曲。
我认为scala是一种非常可扩展的语言,因此无论是使用宏,注释还是其他元编程技术,都应该至少有一种方法来强制执行它。我的问题现在已经足够清楚了吗?
UPDATE2:我相信在仔细研究Scaladoc后我找到了解决方案,角落里隐藏着一条评论:
如果有多个符合条件的参数与隐式参数的类型匹配,则将使用静态重载分辨率的规则选择最具体的参数(请参阅Scala规范§6.26.4):
...
类型参数的隐含范围(2.8.0)
...
所以我需要的是在FooBuilder中编写一个隐式函数:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
implicit def self = this
}
object Foo extends FooBuilder[Foo]
所以每次有人打电话:
default[Foo]
scala将引用类Foo的范围,其中包含对象Foo,其中包含隐式值Foo,并最终找到0参数构造函数。
我认为这个定义比在对象FooBuilder下定义它更好,因为你只能定义一次FooBuilder,因此它不太可扩展。你同意我的意见吗?如果是这样,你能否修改你的答案,以便我能给你一点意见?
答案 0 :(得分:4)
我不明白为什么abstract class
甚至Trait
不允许这样做?
abstract class DefineCreate{
def create(): Unit
}
case class Foo(one: Int)
object Foo extends DefineCreate{
def create(): Unit = { Console.out.println("side-effect") }
}
因此,我强制用户在create
上提出object
方法,因为DefineCreate
的所有实现都必须这样做才能进行编译。
更新以下评论
好吧,不必使用宏等,你可以用类型类实现同样的东西:
trait Constructor[A]{
def create(): A
}
object Construct{
def create[A](implicit cr: Constructor[A]): A = cr.create()
}
没有明确强制伴随对象发芽方法,但如果用户想要使用Constructor.create[Foo]
模式,它会强制用户创建类型类。