[英]In Scala, How to perform compile-time type check on companion object?
在许多语言中但在Scala中却不容易做的事情是:
定义原型“ Super”,这样“ Super”的所有实现都必须定义一个构造函数“ 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 -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,因此它不是很可扩展。 你同意我的观点吗? 如果是这样,您能不能修改一下答案,以便我给您点积分?
我不明白为什么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") }
}
因此,我强迫用户在有问题的object
上create
一个create
方法,因为DefineCreate
所有实现DefineCreate
必须这样做才能进行编译。
更新以下评论
好吧,无需诉诸宏之类的东西,您可以使用类型类实现相同的事情:
trait Constructor[A]{
def create(): A
}
object Construct{
def create[A](implicit cr: Constructor[A]): A = cr.create()
}
这并没有明确地迫使伴随对象萌芽方法,但是如果用户想要使用Constructor.create[Foo]
模式,它确实会迫使用户创建类型类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.