微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何为通用类型定义类型

如何解决如何为通用类型定义类型

我有以下代码

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)

有没有一种方法可以定义类型以简化对类A和B的定义?

类似这样:

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

解决方法

实际上,您不需要类型的别名,而需要绑定的别名。

请参阅How to avoid duplication of type bound in Scala

简而言之,您应该在需要的地方使用F边界。实际上,这不是代码重复。 TTraitA中的类型参数B实际上是三个不同的类型参数,它们可以具有不同的界限。

但是从理论上讲,您可以用macro annotation来简化界限,尽管这不值得,而且通常很危险,因为这对于您的队友来说可能是令人惊讶的,会使调试更加复杂并使IDE混乱。 / p>

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

用法:

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>();
//      ()
//    }
//  };
//  ()
//}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。