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

类型类派生访问默认值

如何解决类型类派生访问默认值

在使用镜像在 Scala 3 中执行类型类派生时,是否有一种干净的方法来访问案例类字段的认值?例如:

case class Foo(s: String = "bar",i: Int,d: Double = Math.PI)

Mirror.Product.MirroredElemLabels 将设置为 ("s","i","d")。有没有类似的东西:(Some["bar"],None,Some[3.141592653589793])

如果不能,可以使用宏来实现吗?我可以同时使用镜像和宏来派生类型类实例吗?

解决方法

您必须编写一个宏,使用名为 concurrency: # Documentation suggests ${{ github.head_ref }},but that's only available on pull_request/pull_request_target triggers,so using ${{ github.ref }}. # On master,we want all builds to complete even if merging happens faster to make it easier to discover at which point something broke. group: ${{ github.ref == 'refs/heads/master' && format('ci-master-{0}',github.sha) || format('ci-{0}',github.ref) }} ,<init>$default$1,... 的方法在伴生对象中工作

<init>$default$2

镜像和宏可以协同工作:

import scala.quoted.*

inline def printDefaults[T]: Unit = ${printDefaultsImpl[T]}

def printDefaultsImpl[T](using Quotes,Type[T]): Expr[Unit] = {
  import quotes.reflect.*

  (1 to 3).map(i =>
    TypeRepr.of[T].typeSymbol
      .companionClass
      .declaredMethod(s"$$lessinit$$greater$$default$$$i")
      .headOption
      .flatMap(_.tree.asInstanceOf[DefDef].rhs)
  ).foreach(println)

 '{()}
}

printDefaults[Foo]
//Some(Literal(Constant(bar)))
//None
//Some(Select(Ident(Math),PI))

用法:

import scala.quoted.*
import scala.deriving.*

trait Default[T] {
  type Out <: Tuple
  def defaults: Out
}

object Default {
  transparent inline given mkDefault[T](using 
    m: Mirror.ProductOf[T],s: ValueOf[Tuple.Size[m.MirroredElemTypes]]
  ): Default[T] =
    new Default[T] {
      type Out = Tuple.Map[m.MirroredElemTypes,Option]
      def defaults = getDefaults[T](s.value).asInstanceOf[Out]
    }

  inline def getDefaults[T](inline s: Int): Tuple = ${getDefaultsImpl[T]('s)}

  def getDefaultsImpl[T](s: Expr[Int])(using Quotes,Type[T]): Expr[Tuple] = {
    import quotes.reflect.*

    val n = s.asTerm.underlying.asInstanceOf[Literal].constant.value.asInstanceOf[Int]

    val terms: List[Option[Term]] =
      (1 to n).toList.map(i =>
        TypeRepr.of[T].typeSymbol
          .companionClass
          .declaredMethod(s"$$lessinit$$greater$$default$$$i")
          .headOption
          .flatMap(_.tree.asInstanceOf[DefDef].rhs)
      )

    def exprOfOption[T](oet: Option[Expr[T]])(using Type[T],Quotes): Expr[Option[T]] = oet match {
      case None => Expr(None)
      case Some(et) => '{Some($et)}
    }

    val exprs: List[Option[Expr[Any]]] = terms.map(_.map(_.asExprOf[Any]))
    val exprs1: List[Expr[Option[Any]]] = exprs.map(exprOfOption)
    Expr.ofTupleFromSeq(exprs1)
  }
}

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