Scala 树匹配案例
Scala Tree Match Case
我对 Scala 还很陌生,对编写宏和寻找一些东西也很陌生 help/advise。我有以下代码...
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))
的树,我试图写一个 match/case
到 select 代表 ValidationRule
的所有表达式。类似于:
case TypeApply(Select(_, ....
任何人都可以提出最佳匹配案例,以便能够从 "is" 方法中提取代表每个 "all" ValidationRules
的树列表吗?
你应该 绝对 研究 Quasiquotes。
Quasiquotes 用于做两件事:构建树和模式匹配树。它们允许您根据等效的 Scala 代码来表达您想要使用的树。您让 quasiquote 库处理 Scala 代码如何映射到树图,这是一件好事!
您可以在 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(), HasLength(255))"
scala> val cq"p => p.name.is($x, $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 =>
???
请记住,宏是一个又深又黑的洞。如果您刚刚起步,预计会花费大量时间让您的宏代码正确无误。之后,预计会花很多时间处理边缘情况。
我对 Scala 还很陌生,对编写宏和寻找一些东西也很陌生 help/advise。我有以下代码...
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))
的树,我试图写一个 match/case
到 select 代表 ValidationRule
的所有表达式。类似于:
case TypeApply(Select(_, ....
任何人都可以提出最佳匹配案例,以便能够从 "is" 方法中提取代表每个 "all" ValidationRules
的树列表吗?
你应该 绝对 研究 Quasiquotes。
Quasiquotes 用于做两件事:构建树和模式匹配树。它们允许您根据等效的 Scala 代码来表达您想要使用的树。您让 quasiquote 库处理 Scala 代码如何映射到树图,这是一件好事!
您可以在 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(), HasLength(255))"
scala> val cq"p => p.name.is($x, $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 =>
???
请记住,宏是一个又深又黑的洞。如果您刚刚起步,预计会花费大量时间让您的宏代码正确无误。之后,预计会花很多时间处理边缘情况。