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

编程入门 行业动态 更新时间:2024-10-25 22:34:15
本文介绍了从宏中获取具有匿名类方法的结构类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

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

Suppose we want to write a macro that defines an anonymous class with some type members or methods, and then creates an instance of that class that's statically typed as a structural type with those methods, etc. This is possible with the macro system in 2.10.0, and the type member part is extremely easy:

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 是 方便特性,它提供了我的 构造函数方法.)

(Where ReflectionUtils is a convenience trait that provides my constructor method.)

这个宏让我们可以将匿名类的类型成员的名称指定为字符串字面量:

This macro lets us specify the name of the anonymous class's type member as a string literal:

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

请注意,它的类型正确.我们可以确认一切正常:

Note that it's appropriately typed. We can confirm that everything's working as expected:

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

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

Now suppose that we try to do the same thing with a method:

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) )) }

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

But when we try it out, we don't get a structural type:

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

但如果我们在其中添加一个额外的匿名类:

But if we stick an extra anonymous class in there:

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.我知道这可能不是定义的行为,但这有什么意义吗?有没有更简洁的方法从宏中获取结构类型(及其上的方法)?

This is extremely handy—it lets you do things like this, for example—but I don't understand why it works, and the type member version works, but not bar. I know this may not be defined behavior, but does it make any sense? Is there an cleaner way to get a structural type (with the methods on it) from a macro?

推荐答案

Travis here 重复回答了这个问题.跟踪器中的问题和 Eugene 的讨论(在评论和邮件列表中)都有链接.

This question is answered in duplicate by Travis here. There are links to the issue in the tracker and to Eugene's discussion (in the comments and mailing list).

在类型检查器著名的Skylla and Charybdis"部分中,我们的英雄决定什么应该摆脱黑暗的匿名性,并将光明视为结构类型的一员.

In the famous "Skylla and Charybdis" section of the type checker, our hero decides what shall escape dark anonymity and see the light as a member of the structural type.

有几种方法可以欺骗类型检查器(这不涉及 Odysseus 的抱羊策略).最简单的方法是插入一个虚拟语句,使该块看起来不像是一个匿名类,然后是它的实例化.

There are a couple of ways to trick the type checker (which do not entail Odysseus's ploy of hugging a sheep). The simplest is to insert a dummy statement so that the block doesn't look like an anonymous class followed by its instantiation.

如果打字员注意到你是一个没有被外界引用的公共术语,它会将你设为私有.

If the typer notices that you're a public term that isn't referenced by the outside, it will make you 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) } }

更多推荐

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

本文发布于:2023-11-07 00:43:08,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1565090.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:类型   结构   方法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!