首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用宏在Dotty中生成类?

如何用宏在Dotty中生成类?
EN

Stack Overflow用户
提问于 2019-12-24 21:26:21
回答 2查看 1.3K关注 0票数 8

是否可以在Dotty,Scala 3中生成一个具有宏的新类?

兹拉贾

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-25 01:46:30

目前在多蒂只有(某种程度上) 。目前还没有(某种) 宏注释,可以生成新成员、新类等。

对于新成员、新类等的生成,可以使用

让我提醒您,即使在Scalac中,生成新成员、新类等的能力也不是从一开始就出现的。这种功能(宏注释)作为Scalac的宏乐园编译器插件出现。

我不能排除某些时候有人会为多蒂写一些像“宏乐园”这样的东西。这还为时尚早,现在只是特性冻结,甚至语言语法(例如)和标准库现在也在不断变化(还有图书馆清单正在测试它们与Dotty的工作能力,例如,目前还没有Scalaz/Cats )。

更新.我们现在可以用Scala 3 (def)宏:用Scala 3宏重写方法生成内部

票数 9
EN

Stack Overflow用户

发布于 2021-04-18 23:02:54

您可以创建一个透明宏,该宏返回一个结构类型以生成任何vals和defs所需的类型。

下面是一个示例;当使用Product调用方法props时,将创建一个具有第一个Product名称为String val的对象。

代码语言:javascript
复制
case class User(firstName: String, age: Int)

// has the type of Props { val firstName: String }
val userProps = props[User]

println(userProps.firstName) // prints "prop for firstName"
println(userProps.lastName) // compile error

而实现则有点棘手,但也不算太糟:

代码语言:javascript
复制
import scala.compiletime.*
import scala.quoted.*
import scala.deriving.Mirror

class Props extends Selectable:
  def selectDynamic(name: String): Any =
    "prop for " + name

transparent inline def props[T] =
  ${ propsImpl[T] }

private def propsImpl[T: Type](using Quotes): Expr[Any] =
  import quotes.reflect.*

  Expr.summon[Mirror.ProductOf[T]].get match
    case '{ $m: Mirror.ProductOf[T] {type MirroredElemLabels = mels; type MirroredElemTypes = mets } } =>
      Type.of[mels] match
        case '[mel *: melTail] =>
          val label = Type.valueOfConstant[mel].get.toString

          Refinement(TypeRepr.of[Props], label, TypeRepr.of[String]).asType match
            case '[tpe] =>
              val res = '{
                val p = Props()
                p.asInstanceOf[tpe]
              }
              println(res.show)
              res

使用递归,您可以细化精化(因为细化了<:TypeRepr),直到所有的内容都被构建出来。

尽管如此,使用transparent inline甚至Scala 2宏注释来生成新类型使得IDE很难支持自动完成。因此,如果可能的话,我建议使用标准的台风求导

您甚至可以导出标准特征的默认行为:

代码语言:javascript
复制
trait SpringDataRepository[E, Id]:
  def findAll(): Seq[E]

trait DerivedSpringDataRepository[E: Mirror.ProductOf, Id]:
  def findAll(): Seq[E] = findAllDefault[E, Id]()
  
private inline def findAllDefault[E, Id](using m: Mirror.ProductOf[E]): Seq[E] =
  findAllDefaultImpl[E, m.MirroredLabel, m.MirroredElemLabels]()

private inline def findAllDefaultImpl[E, Ml, Mels](columns: ArrayBuffer[String] = ArrayBuffer()): Seq[E] =
  inline erasedValue[Mels] match
    case _: EmptyTuple =>
      // base case
      println("executing.. select " + columns.mkString(", ") + " from " + constValue[Ml])
      Seq.empty[E]
    case _: (mel *: melTail) =>
      findAllDefaultImpl[E, Ml, melTail](columns += constValue[mel].toString) 

然后,用户所要做的就是用他们的产品类型扩展DerivedSpringDataRepository

代码语言:javascript
复制
case class User(id: Int, first: String, last: String)

class UserRepo extends DerivedSpringDataRepository[User, Int]

val userRepo = UserRepo()

userRepo.findAll() // prints "executing.. select id, first, last from User"
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59473523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档