如何使用宏中计算的类型 Scala, 在句子中 reify?

我合作了 Scala Macros 我在宏中有以下代码:


val fieldMemberType = fieldMember.typeSignatureIn/objectType/ match {
case NullaryMethodType/tpe/ => tpe
case _ => doesntCompile/s"$propertyName isn't a field, it must be another thing"/
}

reify{
new TypeBuilder// {
type fieldType = fieldMemberType.type
}
}


你可以看到,我设法得到了
c.universe.Type fieldMemberType

. 这表示对象中的特定字段的类型。 一旦我得到它,我想创建一个新对象
TypeBuilder

在 reify.
TypeBuilder

- 它是一个带有抽象参数的抽象类。 这个抽象参数是相等的
fieldType

. 我要这个
fieldType

这是我之前发现的类型。

运行此处显示的代码返回me
fieldMemberType not found

. 有没有办法武力
fieldMemberType

在句子里面工作 reify?
已邀请:

喜特乐

赞同来自:

问题是您传递的代码
reify

, 事实上,当宏观扩展时,它将被祈祷,并且
fieldMemberType

那里没有意义。

在某些情况下,您可以使用
splice

, 要拖动您在宏扩展期间所拥有的表达式,请进入您加权的代码。 例如,如果我们尝试创建此功能的实例:


trait Foo { def i: Int }


在宏观扩展期间有此变量:


val myInt = 10


我们可以写下列:


reify { new Foo { def i = c.literal/myInt/.splice } }


在这里它不起作用,因此您将不得不忘记大幅
reify

和写 AST 从手。 不幸的是,你会发现它发生了很多事情。 我的标准方法是推出一个新的方法 REPL 并介绍这样的东西:


import scala.reflect.runtime.universe._

trait TypeBuilder { type fieldType }

showRaw/reify/new TypeBuilder { type fieldType = String }//


这将备用几行。 AST, 然后,您可以将其切入宏定义作为起点。 然后你 fiddle 和他一起,更换这样的东西:


Ident/TypeBuilder/


有了这个:


Ident/newTypeName/"TypeBuilder"//



FINAL


Flag.FINAL

, 等等。 我想要方法
toString

适用于类型 AST 更准确地对应创建它们所需的代码,但您将快速理解您需要更改的内容。 你将结束这样的东西:


c.Expr/
Block/
ClassDef/
Modifiers/Flag.FINAL/,
anon,
Nil,
Template/
Ident/newTypeName/"TypeBuilder"// :: Nil,
emptyValDef,
List/
constructor/c/,
TypeDef/
Modifiers//,
newTypeName/"fieldType"/,
Nil,
TypeTree/fieldMemberType/
/
/
/
/,
Apply/Select/New/Ident/anon//, nme.CONSTRUCTOR/, Nil/
/
/


在哪里
anon

- 这是您为您的匿名类提前创建的类型的名称,
constructor

- 这是一种方便的方法,我用来让这种事情变得不那么恶心 /你可以在最后找到他的定义。
https://gist.github.com/4249936
/.

现在,如果我们在类似的东西中遵守这种表达 , 我们可以写下列:


scala> TypeMemberExample.builderWithType[String]
res0: TypeBuilder{type fieldType = String} = $1$$1@fb3f1f3


所以它有效。 我们拍了
c.universe.Type

/从这里到达哪个
WeakTypeTag

键入b型参数
builderWithType

, 但它将与任何旧的方式工作
Type

/ 并用它来确定我们标志类型的成员
TypeBuilder

.

涵秋

赞同来自:

对于您的使用选项,有一种比写树更简单的方法。 事实上,我一直在使用它来保持一定距离的树木,因为它可能很难用树木。 我更愿意计算类型并用来散发成树木。 它可以更可靠和更可靠 "hygienic" macros 少于编译时间错误。 IMO 使用树的使用应该是最新的工具,只在某些情况下,例如转换树木或通用编程,为一系列类型,例如故事。

这里的建议是确定接受要在正文中使用的类型类型类型的函数 reify, 附有上下文 WeakTypeTag. 然后你打电话给这个功能,明确传递 WeakTypeTags, 由于该方法,您可以从Universe类型构建 context WeakTypeTag.

所以在你的情况下,它将提供以下内容。


val fieldMemberType: Type = fieldMember.typeSignatureIn/objectType/ match {
case NullaryMethodType/tpe/ => tpe
case _ => doesntCompile/s"$propertyName isn't a field, it must be another thing"/
}

def genRes[T: WeakTypeTag] = reify{
new TypeBuilder// {
type fieldType = T
}
}

genRes/c.WeakTypeTag/fieldMemberType//

要回复问题请先登录注册