Scala:创建一个特征,强制 类 重新实现某些方法
Scala: Creating a trait that forces classes to re-implement certain methods
我正在尝试实现一个特征,强制每个 class 扩展它(并且不是抽象的)来实现某些方法(即使它们已经存在于 super-classes 中)。具体应该是这样的:
trait Debugable {
override def hashCode(): Int = ???
override def equals(obj: Any): Boolean = ???
override def toString: String = ???
}
这是特征,这是实现:
class TestClass {
}
object TestClass{
def main(args: Array[String]): Unit = {
val t = new TestClass
println(t)
}
}
理想情况下,上面的代码不应编译(因为可调试的 class 不会实现所需的方法)。实际上,这不仅会编译,而且不会抛出 运行 时间异常(它只采用对象的默认实现 class)。
到目前为止,没有任何东西能够产生预期的行为。我认为宏可以提供帮助,但我不确定宏是否可以表达如下内容:
foreach class
if class.traits.contains(debugable)
return class.methods.contains(toString)
我知道我可以让一些外部脚本进行检查并将其与 gradle 编译任务捆绑在一起,但我希望有一个可以作为项目本身的一部分实施的解决方案(因为这将使它独立于所使用的构建管道,因为它应该 maintain/extend 比编写爬行整个源代码的脚本更简单和容易)
在我看来,您应该将其抽象化。
// Start writing your ScalaFiddle code here
trait Debugable {
def debugHashCode:Int
def debugEquals(obj: Any): Boolean
def debugToString: String
override def hashCode(): Int = debugHashCode
override def equals(obj: Any): Boolean = debugEquals(obj)
override def toString: String = debugToString
}
//this will not compile
class TestClass extends Debugable { }
//this is OK but you need to implement 3 methods later :)
abstract class TestClass2 extends Debugable {}
https://scalafiddle.io/sf/bym3KFM/0
宏应该是您最后尝试的东西。
This is close to it (and certainly an improvement over what I have),
but it does not do exactly what I wanted. If I have a "chain" of
classes, then it is enough for the top of the chain to implement the
methods.
Typeclass 方法可以帮助解决这个问题,例如,
trait Debuggable[T] {
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
class Foo
class Bar
class Qux extends Foo
object Debuggable {
implicit val fooDebuggable: Debuggable[Foo] = new Debuggable[Foo] {
def hashCode(v: Foo) = 42
def equals(v: Foo, b: Any) = true
def toString(v: Foo) = "woohoo"
}
implicit val barDebuggable: Debuggable[Bar] = new Debuggable[Bar] {
def hashCode(v: Bar) = 24
def equals(v: Bar, b: Any) = false
def toString(v: Bar) = "boohoo"
}
}
import Debuggable._
def debug[T](v: T)(implicit ev: Debuggable[T]) = ???
debug(new Foo) // OK
debug(new Bar) // OK
debug(new Qux) // Error despite Qux <:< Foo
基于此我写了以下内容,它满足了我的需要并且确实覆盖了默认实现:
trait Debuggable_Helper[T]{
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
trait Debuggable[T] extends Debuggable_Helper [Debuggable [T]]{
override def hashCode(): Int = hashCode(this)
override def equals(b: Any): Boolean = equals(this, b)
override def toString(): String = toString(this)
}
class Foo extends Debuggable[Foo]{
def hashCode(v: Debuggable[Foo]) = 42
def equals(v: Debuggable[Foo], b: Any) = true
def toString(v: Debuggable[Foo]) = "woohoo"
}
class Qux extends Foo with Debuggable[Qux] //does not compile
object Test{
def main(args: Array[String]): Unit = {
println(new Foo) // OK - prints 'woohoo'
}
}
我正在尝试实现一个特征,强制每个 class 扩展它(并且不是抽象的)来实现某些方法(即使它们已经存在于 super-classes 中)。具体应该是这样的:
trait Debugable {
override def hashCode(): Int = ???
override def equals(obj: Any): Boolean = ???
override def toString: String = ???
}
这是特征,这是实现:
class TestClass {
}
object TestClass{
def main(args: Array[String]): Unit = {
val t = new TestClass
println(t)
}
}
理想情况下,上面的代码不应编译(因为可调试的 class 不会实现所需的方法)。实际上,这不仅会编译,而且不会抛出 运行 时间异常(它只采用对象的默认实现 class)。
到目前为止,没有任何东西能够产生预期的行为。我认为宏可以提供帮助,但我不确定宏是否可以表达如下内容:
foreach class
if class.traits.contains(debugable)
return class.methods.contains(toString)
我知道我可以让一些外部脚本进行检查并将其与 gradle 编译任务捆绑在一起,但我希望有一个可以作为项目本身的一部分实施的解决方案(因为这将使它独立于所使用的构建管道,因为它应该 maintain/extend 比编写爬行整个源代码的脚本更简单和容易)
在我看来,您应该将其抽象化。
// Start writing your ScalaFiddle code here
trait Debugable {
def debugHashCode:Int
def debugEquals(obj: Any): Boolean
def debugToString: String
override def hashCode(): Int = debugHashCode
override def equals(obj: Any): Boolean = debugEquals(obj)
override def toString: String = debugToString
}
//this will not compile
class TestClass extends Debugable { }
//this is OK but you need to implement 3 methods later :)
abstract class TestClass2 extends Debugable {}
https://scalafiddle.io/sf/bym3KFM/0
宏应该是您最后尝试的东西。
This is close to it (and certainly an improvement over what I have), but it does not do exactly what I wanted. If I have a "chain" of classes, then it is enough for the top of the chain to implement the methods.
Typeclass 方法可以帮助解决这个问题,例如,
trait Debuggable[T] {
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
class Foo
class Bar
class Qux extends Foo
object Debuggable {
implicit val fooDebuggable: Debuggable[Foo] = new Debuggable[Foo] {
def hashCode(v: Foo) = 42
def equals(v: Foo, b: Any) = true
def toString(v: Foo) = "woohoo"
}
implicit val barDebuggable: Debuggable[Bar] = new Debuggable[Bar] {
def hashCode(v: Bar) = 24
def equals(v: Bar, b: Any) = false
def toString(v: Bar) = "boohoo"
}
}
import Debuggable._
def debug[T](v: T)(implicit ev: Debuggable[T]) = ???
debug(new Foo) // OK
debug(new Bar) // OK
debug(new Qux) // Error despite Qux <:< Foo
基于此我写了以下内容,它满足了我的需要并且确实覆盖了默认实现:
trait Debuggable_Helper[T]{
def hashCode(v: T): Int
def equals(v: T, b: Any): Boolean
def toString(v: T): String
}
trait Debuggable[T] extends Debuggable_Helper [Debuggable [T]]{
override def hashCode(): Int = hashCode(this)
override def equals(b: Any): Boolean = equals(this, b)
override def toString(): String = toString(this)
}
class Foo extends Debuggable[Foo]{
def hashCode(v: Debuggable[Foo]) = 42
def equals(v: Debuggable[Foo], b: Any) = true
def toString(v: Debuggable[Foo]) = "woohoo"
}
class Qux extends Foo with Debuggable[Qux] //does not compile
object Test{
def main(args: Array[String]): Unit = {
println(new Foo) // OK - prints 'woohoo'
}
}