简体   繁体   English

如何为泛型类型定义类型

[英]How to define a type for a generic type

Say I have the following code:假设我有以下代码:

trait Trait[T <: Trait[T]] {
  def merge(t: T): T
}

case class A[T <: Trait[T]](t: T, i: Int)
case class B[T <: Trait[T]](t: T, str: String)

Is there a way I can define a type to abbreviate my definitions of classes A and B?有没有一种方法可以定义一种类型来缩写我对 A 类和 B 类的定义?

So something like:所以像:

type T2 = _ <: Trait[T2] // ???
case class A[T2](t: T2, i: Int)
case class B[T2](t: T2, str: String)

Actually, you don't want an alias for a type, you want an alias for a bound.实际上,您不需要类型的别名,而是需要绑定的别名。

Please see How to avoid duplication of type bound in Scala请参阅如何避免在 Scala 中重复类型绑定

Briefly, you should keep F-bounds wherever you need them.简而言之,您应该在需要的地方保留 F 边界。 Actually, this is not a code duplication.实际上,这不是代码重复。 Type parameter T of Trait , A , B are actually three different type parameters, which can have different bounds. TraitAB类型参数T实际上是三个不同的类型参数,它们可以有不同的界限。

But theoretically you can abbreviate bounds with a macro annotation , although this is not worth it and generally can be dangerous, because this can be surprising for your team mates, can make debugging more complicated and can confuse your IDE但理论上您可以使用 宏注释来缩写边界,尽管这样做并不值得,而且通常会很危险,因为这可能会让您的队友感到惊讶,会使调试变得更加复杂,并且会使您的 IDE 感到困惑

import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

@compileTimeOnly("enable macro annotations")
class fbound extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro FBoundMacro.impl
}

object FBoundMacro {
  def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
    import c.universe._

    def addFBound(tparam: Tree): Tree = tparam match {
      case q"$mods type $name[..$tparams] >: $low <: $high" =>
        val tparamsNames = tparams.map {
          case q"$_ type $nme[..$_] >: $_ <: $_" => nme
        }
        val fBound = tq"Trait[$name[..$tparamsNames]]"
        val high1 = high match {
          case tq"$EmptyTree" => fBound
          case tq"..$withTypes { ..$refinements }" =>
            val withTypes1 = withTypes :+ fBound
            tq"..$withTypes1 { ..$refinements }"
          case tq"$typ" => tq"$typ with $fBound"
        }
        q"$mods type $name[..$tparams] >: $low <: $high1"
    }

    annottees match {
      case q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }" :: tail =>
        val tparams1 = addFBound(tparams.head) :: tparams.tail
        q"""
          $mods class $tpname[..$tparams1] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }
          ..$tail
        """
    }
  }
}

Usage:用法:

trait Trait[T <: Trait[T]] {
  def merge(t: T): T
}

@fbound case class A[T](t: T, i: Int)
@fbound case class B[T](t: T, str: String)

//scalac: {
//  case class A[T <: Trait[T]] extends scala.Product with scala.Serializable {
//    <caseaccessor> <paramaccessor> val t: T = _;
//    <caseaccessor> <paramaccessor> val i: Int = _;
//    def <init>(t: T, i: Int) = {
//      super.<init>();
//      ()
//    }
//  };
//  ()
//}
//scalac: {
//  case class B[T <: Trait[T]] extends scala.Product with scala.Serializable {
//    <caseaccessor> <paramaccessor> val t: T = _;
//    <caseaccessor> <paramaccessor> val str: String = _;
//    def <init>(t: T, str: String) = {
//      super.<init>();
//      ()
//    }
//  };
//  ()
//}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM