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'
  }
}