gpt4 book ai didi

scala - 从宏中获取具有匿名类方法的结构类型

转载 作者:行者123 更新时间:2023-12-03 04:14:00 25 4
gpt4 key购买 nike

假设我们想要编写一个宏,它定义一个具有某些类型成员或方法的匿名类,然后创建该类的一个实例,该实例使用这些方法等静态类型化为结构类型。这可以通过宏系统实现在2.10.0中,类型成员部分非常简单:

object MacroExample extends ReflectionUtils {
import scala.language.experimental.macros
import scala.reflect.macros.Context

def foo(name: String): Any = macro foo_impl
def foo_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._

val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)

c.Expr(Block(
ClassDef(
Modifiers(Flag.FINAL), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
TypeDef(Modifiers(), newTypeName(lit), Nil, TypeTree(typeOf[Int]))
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
))
}
}

(其中ReflectionUtils是一个convenience trait,它提供了我的构造函数方法。)

这个宏允许我们将匿名类的类型成员的名称指定为字符串文字:

scala> MacroExample.foo("T")
res0: AnyRef{type T = Int} = $1$$1@7da533f6

请注意,输入的内容正确。我们可以确认一切都按预期进行:

scala> implicitly[res0.T =:= Int]
res1: =:=[res0.T,Int] = <function1>

现在假设我们尝试用一个方法做同样的事情:

def bar(name: String): Any = macro bar_impl
def bar_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._

val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)

c.Expr(Block(
ClassDef(
Modifiers(Flag.FINAL), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
DefDef(
Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
c.literal(42).tree
)
)
)
),
Apply(Select(New(Ident(anon)), nme.CONSTRUCTOR), Nil)
))
}

但是当我们尝试时,我们没有得到结构类型:

scala> MacroExample.bar("test")
res1: AnyRef = $1$$1@da12492

但是如果我们在那里添加一个额外的匿名类:

def baz(name: String): Any = macro baz_impl
def baz_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._

val Literal(Constant(lit: String)) = name.tree
val anon = newTypeName(c.fresh)
val wrapper = newTypeName(c.fresh)

c.Expr(Block(
ClassDef(
Modifiers(), anon, Nil, Template(
Nil, emptyValDef, List(
constructor(c.universe),
DefDef(
Modifiers(), newTermName(lit), Nil, Nil, TypeTree(),
c.literal(42).tree
)
)
)
),
ClassDef(
Modifiers(Flag.FINAL), wrapper, Nil,
Template(Ident(anon) :: Nil, emptyValDef, constructor(c.universe) :: Nil)
),
Apply(Select(New(Ident(wrapper)), nme.CONSTRUCTOR), Nil)
))
}

它有效:

scala> MacroExample.baz("test")
res0: AnyRef{def test: Int} = $2$$1@6663f834

scala> res0.test
res1: Int = 42

这非常方便——它可以让你做类似 this 的事情,例如,但我不明白为什么它有效,并且类型成员版本有效,但 bar 无效。我知道这个may not be defined behavior ,但这有什么意义吗?是否有更清晰的方法从宏获取结构类型(及其方法)?

最佳答案

Travis here 重复回答了这个问题。跟踪器中有指向该问题的链接以及尤金的讨论(在评论和邮件列表中)。

在类型检查器著名的“Skylla 和 Charybdis”部分中,我们的英雄决定什么将逃脱黑暗的匿名并作为结构类型的成员看到光明。

有几种方法可以欺骗类型检查器(这不需要奥德修斯拥抱羊的策略)。最简单的方法是插入一个虚拟语句,以便该 block 看起来不像是一个匿名类,然后是它的实例化。

如果打字者注意到您是一个未被外部引用的公共(public)术语,它会将您设为私有(private)。

object Mac {
import scala.language.experimental.macros
import scala.reflect.macros.Context

/* Make an instance of a structural type with the named member. */
def bar(name: String): Any = macro bar_impl

def bar_impl(c: Context)(name: c.Expr[String]) = {
import c.universe._
val anon = TypeName(c.freshName)
// next week, val q"${s: String}" = name.tree
val Literal(Constant(s: String)) = name.tree
val A = TermName(s)
val dmmy = TermName(c.freshName)
val tree = q"""
class $anon {
def $A(i: Int): Int = 2 * i
}
val $dmmy = 0
new $anon
"""
// other ploys
//(new $anon).asInstanceOf[{ def $A(i: Int): Int }]
// reference the member
//val res = new $anon
//val $dmmy = res.$A _
//res
// the canonical ploy
//new $anon { } // braces required
c.Expr(tree)
}
}

关于scala - 从宏中获取具有匿名类方法的结构类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14370842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com