如何在自身类型中自动继承 mixin 泛型?

How to automatically inherit mixin generic type in self-types?

如何从父混入类型继承泛型?例如,我有一个特征 Foo 和一个通用类型 A:

trait Foo[A] {
  def value: A
}

我有一个使用 Foo[String] 的 class User,例如:

class User extends Foo[String] {
  override def value: String = ???
}

一切正常。现在,我想添加一个自我类型为 Foo[A] 的特征 Bar[A]

trait Bar[A] { self: Foo[A] =>
  def anotherValue: A
}

如果我想在 User 中使用 Bar,我需要做:

class User extends Foo[String] with Bar[String] {
  override def value: String = ???
  override def anotherValue: String = ???
}

有什么方法可以简化 User 吗? (Bar 自动从相应的 Foo 推断类型。)

class User extends Foo[String] with Bar 

您可以定义中间特征

trait UserLike[A] extends Foo[A] with Bar[A]

class User extends UserLike[String] {
  override def value: String = ???
  override def anotherValue: String = ???
}

您可以定义一个 macro annotation 但这会有点矫枉过正

@extendsBar
class User extends Foo[String] {
  override def value: String = ???
  override def anotherValue: String = ???
}

//scalac: {
//  class User extends Foo[String] with Bar[String] {
//    def <init>() = {
//      super.<init>();
//      ()
//    };
//    override def value: String = $qmark$qmark$qmark;
//    override def anotherValue: String = $qmark$qmark$qmark
//  };
//  ()
//}

import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class extendsBar extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro ExtendsBarMacro.impl
}

object ExtendsBarMacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._
    annottees match {
      case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: tail =>
        val fooArg = parents.collectFirst {
          case tq"Foo[$t]" => t
        }.getOrElse(c.abort(c.enclosingPosition, "class must extend Foo"))
        val parents1 = parents :+ tq"Bar[$fooArg]"
        q"""
           $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents1 { $self => ..$stats }
           ..$tail
        """
      case _ =>
        c.abort(c.enclosingPosition, "annottee must be a class")
    }
  }
}

如果 A 是类型成员而不是类型参数,这会更灵活

trait Foo {
  type A
  def value: A
}

trait Bar { self: Foo =>
  def anotherValue: A
}

class User extends Foo with Bar {
  override type A = String
  override def value: String = ???
  override def anotherValue: String = ???
}