加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

斯卡拉树比赛案例

发布时间:2020-12-16 18:34:06 所属栏目:安全 来源:网络整理
导读:我是 Scala的新手,对于编写宏并寻找一些帮助/建议非常陌生.我有以下代码…… trait ValidationRulecase class Required() extends ValidationRulecase class HasLength(l: Int) extends ValidationRulecase class Person(name: String)myMacro[Person] { p =
我是 Scala的新手,对于编写宏并寻找一些帮助/建议非常陌生.我有以下代码……

trait ValidationRule
case class Required() extends ValidationRule
case class HasLength(l: Int) extends ValidationRule
case class Person(name: String)

myMacro[Person] { p => p.name.is(Required(),HasLength(255)) }

显然这里有一些丢失的代码,但这只是伪问题.

所以给定一个代表p =>的树. p.name.is(Required(),HasLength(255))我正在尝试编写一个匹配/大小写来选择代表ValidationRule的所有表达式.就像是:

case TypeApply(Select(_,....

任何人都可以提出最佳匹配案例,以便能够从“is”方法中提取代表每个“所有”ValidationRules的树列表吗?

解决方法

你一定要看看 Quasiquotes.

Quasiquotes用于做两件事:构建树,以及模式匹配树.它们允许您根据等效的Scala代码表达要使用的树.你让quasiquote库处理Scala代码映射到Tree图的方式,这是一件好事!

您可以在REPL中使用它们,尽管宏结构中的结果可能略有不同:

scala> import scala.reflect.runtime.universe._
scala> showRaw(cq"p => p.name.is(Required(),HasLength(255))")

res0: String = CaseDef(
  Bind(
    TermName("p"),Ident(termNames.WILDCARD)),EmptyTree,Apply(
    Select(
      Select(
        Ident(TermName("p")),TermName("name")),TermName("is")),List(
      Apply(
        Ident(TermName("Required")),List()),Apply(
        Ident(TermName("HasLength")),List(Literal(Constant(255)))))))

你可以用Quasiquotes做的另一件事是实际使用它们进行模式匹配.

scala> val fromTree = cq"p => p.name.is(Required(),HasLength(255))"
scala> val cq"p => p.name.is($x,$y)" = fromTree


x: reflect.runtime.universe.Tree = Required()
y: reflect.runtime.universe.Tree = HasLength(255)

现在,您必须要小心,因为如果用户将其模式变量命名为p,则该模式仅匹配.

scala> val fromTree = cq"x => x.name.is(Required(),$y)" = fromTree

scala.MatchError: case (x @ _) => x.name.is(Required(),HasLength(255)) (of class scala.reflect.internal.Trees$CaseDef)
  ... 33 elided

相反,你会想要更通用一点:

scala> val cq"${p1:TermName} => ${p2:TermName}.name.is($x,$y)" = fromTree
p1: reflect.runtime.universe.TermName = x
p2: reflect.runtime.universe.TermName = x
x: reflect.runtime.universe.Tree = Required()
y: reflect.runtime.universe.Tree = HasLength(255)

scala> p1 == p2
res2: Boolean = true

当然,如果您在模式匹配中执行此操作,则可以执行以下操作:

case cq"${p1:TermName} => ${p2:TermName}.name.is($x,$y)" if p1 == p2 => 
  ???

请记住,宏是一个深洞,黑洞.如果您刚开始使用,则需要花费大量时间来使宏代码正确无误.在此之后,期望花费大量时间处理边缘情况.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读