如何在自身类型中自动继承 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 = ???
}
如何从父混入类型继承泛型?例如,我有一个特征 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 = ???
}