Skip to content

Commit d290eae

Browse files
authored
Merge pull request #1836 from jxnu-liguobin/wip/add-environment
2 parents 8e0fb45 + af6843a commit d290eae

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
---
2+
layout: multipage-overview
3+
title: Environment, Universes, and Mirrors
4+
partof: reflection
5+
overview-name: Reflection
6+
7+
num: 2
8+
language: zh-cn
9+
---
10+
11+
<span class="label important" style="float: right;">EXPERIMENTAL</span>
12+
13+
## Environment
14+
15+
反射环境根据反射工作是在运行时还是在编译时完成而有所不同。在运行时和编译时使用的环境之间的区别被封装在一个所谓的 *宇宙(universe)* 中。
16+
反射环境的另一个重要方面是我们可以反射的访问一组实体。这组实体由所谓的 *镜像(mirror)* 决定。
17+
18+
例如,可通过运行时反射访问的实体由`ClassloaderMirror`提供。该镜像仅提供对由特定类加载器加载的实体(包,类型和成员)的访问。
19+
20+
镜像不仅可以确定反射访问的实体集。它们还提供对这些实体执行的反射操作。例如,在运行时反射中,可以使用*调用者镜像*(invoker mirror)来调用类的方法或构造函数。
21+
22+
## Universes
23+
24+
宇宙有两种主要类型 - 由于同时具有运行时和编译时反射功能,一个人必须使用与即将完成的工作相对应的宇宙。二者之一:
25+
26+
- `scala.reflect.runtime.universe` 用于 **运行时反射**,或者
27+
- `scala.reflect.macros.Universe` 用于 **编译时反射**
28+
29+
一个宇宙提供了反射中使用的所有主要概念的接口,例如类型(`Types`),树(`Trees`)和注解(`Annotations`)。
30+
31+
## Mirrors
32+
33+
反射提供的所有信息都可以通过*镜像*访问。根据要获得的信息类型或要采取的反射动作,必须使用不同类型的镜像。*类加载器镜像*可用于获取类型和成员的表示。
34+
从类加载器镜像中,可以获得更专门的*调用者*镜像(最常用的镜像),这些镜像实现了反射调用,例如方法或构造函数调用以及字段访问。
35+
36+
总结:
37+
38+
- **"类加载器" 镜像**。这些镜像将名称转换为符号 (通过方法 `staticClass`/`staticModule`/`staticPackage`)。
39+
40+
- **"调用者" 镜像**。这些镜像实现反射调用(通过方法 `MethodMirror.apply``FieldMirror.get`,等等。)。这些"调用者"镜像是最常用的镜像类型。
41+
42+
### Runtime Mirrors
43+
44+
在运行时使用的镜像的入口点是通过`ru.runtimeMirror(<classloader>)`,其中`ru``scala.reflect.runtime.universe`
45+
46+
一个`scala.reflect.api.JavaMirrors#runtimeMirror`的调用结果是一个类型为`scala.reflect.api.Mirrors#ReflectiveMirror`的类加载器镜像,它可以按名称加载符号。
47+
48+
一个类加载器镜像可以创建多个调用者镜像(包括`scala.reflect.api.Mirrors#InstanceMirror``scala.reflect.api.Mirrors#MethodMirror``scala.reflect.api.Mirrors#FieldMirror``scala.reflect.api.Mirrors#ClassMirror`,和`scala.reflect.api.Mirrors#ModuleMirror`)。
49+
50+
下面提供了这两种类型的反射镜像如何相互作用的示例。
51+
52+
### Types of Mirrors, Their Use Cases & Examples
53+
54+
`ReflectiveMirror`用于按名称加载符号,并用作调用者镜像的入口。入口点:`val m = ru.runtimeMirror(<classloader>)`。例如:
55+
56+
scala> val ru = scala.reflect.runtime.universe
57+
ru: scala.reflect.api.JavaUniverse = ...
58+
59+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
60+
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
61+
62+
`InstanceMirror`用于为方法和字段以及内部类和内部对象(模块)创建调用者镜像。入口点:`val im = m.reflect(<value>)`。例如:
63+
64+
scala> class C { def x = 2 }
65+
defined class C
66+
67+
scala> val im = m.reflect(new C)
68+
im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
69+
70+
`MethodMirror`用于调用实例方法(Scala仅具有实例方法-对象的方法是对象实例的实例方法,可通过`ModuleMirror.instance`获得)。入口点:`val mm = im.reflectMethod(<method symbol>)`)。例如:
71+
72+
scala> val methodX = ru.typeOf[C].decl(ru.TermName("x")).asMethod
73+
methodX: scala.reflect.runtime.universe.MethodSymbol = method x
74+
75+
scala> val mm = im.reflectMethod(methodX)
76+
mm: scala.reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e)
77+
78+
scala> mm()
79+
res0: Any = 2
80+
81+
`FieldMirror`用于获取/设置实例字段(与方法类似,Scala仅具有实例字段,请参见上文)。入口点:`val fm = im.reflectField(<field or accessor symbol>)`。例如:
82+
83+
scala> class C { val x = 2; var y = 3 }
84+
defined class C
85+
86+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
87+
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
88+
89+
scala> val im = m.reflect(new C)
90+
im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1
91+
92+
scala> val fieldX = ru.typeOf[C].decl(ru.TermName("x")).asTerm.accessed.asTerm
93+
fieldX: scala.reflect.runtime.universe.TermSymbol = value x
94+
95+
scala> val fmX = im.reflectField(fieldX)
96+
fmX: scala.reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1)
97+
98+
scala> fmX.get
99+
res0: Any = 2
100+
101+
scala> fmX.set(3)
102+
103+
scala> val fieldY = ru.typeOf[C].decl(ru.TermName("y")).asTerm.accessed.asTerm
104+
fieldY: scala.reflect.runtime.universe.TermSymbol = variable y
105+
106+
scala> val fmY = im.reflectField(fieldY)
107+
fmY: scala.reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1)
108+
109+
scala> fmY.get
110+
res1: Any = 3
111+
112+
scala> fmY.set(4)
113+
114+
scala> fmY.get
115+
res2: Any = 4
116+
117+
`ClassMirror`用于为构造函数创建调用者镜像。入口点:对于静态类`val cm1 = m.reflectClass(<class symbol>)`,对于内部类`val mm2 = im.reflectClass(<class symbol>)`。例如:
118+
119+
scala> case class C(x: Int)
120+
defined class C
121+
122+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
123+
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
124+
125+
scala> val classC = ru.typeOf[C].typeSymbol.asClass
126+
classC: scala.reflect.runtime.universe.Symbol = class C
127+
128+
scala> val cm = m.reflectClass(classC)
129+
cm: scala.reflect.runtime.universe.ClassMirror = class mirror for C (bound to null)
130+
131+
scala> val ctorC = ru.typeOf[C].decl(ru.termNames.CONSTRUCTOR).asMethod
132+
ctorC: scala.reflect.runtime.universe.MethodSymbol = constructor C
133+
134+
scala> val ctorm = cm.reflectConstructor(ctorC)
135+
ctorm: scala.reflect.runtime.universe.MethodMirror = constructor mirror for C.<init>(x: scala.Int): C (bound to null)
136+
137+
scala> ctorm(2)
138+
res0: Any = C(2)
139+
140+
`ModuleMirror`用于访问单例对象的实例。入口点:对于静态对象`val mm1 = m.reflectModule(<module symbol>)`,对于内部对象`val mm2 = im.reflectModule(<module symbol>)`。例如:
141+
142+
scala> object C { def x = 2 }
143+
defined module C
144+
145+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
146+
m: scala.reflect.runtime.universe.Mirror = JavaMirror ...
147+
148+
scala> val objectC = ru.typeOf[C.type].termSymbol.asModule
149+
objectC: scala.reflect.runtime.universe.ModuleSymbol = object C
150+
151+
scala> val mm = m.reflectModule(objectC)
152+
mm: scala.reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null)
153+
154+
scala> val obj = mm.instance
155+
obj: Any = C$@1005ec04
156+
157+
### Compile-Time Mirrors
158+
159+
编译时镜像仅使用类加载器镜像来按名称加载符号。
160+
161+
类加载器镜像的入口点通过`scala.reflect.macros.Context#mirror`。使用类加载器镜像的典型方法包括`scala.reflect.api.Mirror#staticClass``scala.reflect.api.Mirror#staticModule``scala.reflect.api.Mirror#staticPackage`。例如:
162+
163+
import scala.reflect.macros.Context
164+
165+
case class Location(filename: String, line: Int, column: Int)
166+
167+
object Macros {
168+
def currentLocation: Location = macro impl
169+
170+
def impl(c: Context): c.Expr[Location] = {
171+
import c.universe._
172+
val pos = c.macroApplication.pos
173+
val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object
174+
c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column)))))
175+
}
176+
}
177+
178+
注意:有几种高级替代方法,可以避免必须手动查找符号。例如,`typeOf[Location.type].termSymbol`(如果需要`ClassSymbol`,则为`typeOf[Location].typeSymbol`),因为我们不必使用字符串来查找符号,所以它们是类型安全的。

0 commit comments

Comments
 (0)