8000 Merge pull request #185 from scalajp/ja/reflection · phaller/scala.github.com@27311a8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 27311a8

Browse files
committed
Merge pull request scala#185 from scalajp/ja/reflection
[Translation to Japanese] Reflection overview
2 parents 169cbe0 + 3e8903b commit 27311a8

14 files changed

+1841
-2
lines changed

ja/overviews/core/reflection.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
layout: overview
3+
partof: reflection
4+
overview: reflection
5+
language: ja
6+
label-color: important
7+
label-text: Experimental
8+
title: リフレクション
9+
---

ja/overviews/reflection/annotations-names-scopes.md

Lines changed: 410 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
---
2+
layout: overview-large
3+
4+
disqus: true
5+
6+
partof: reflection
7+
num: 2
8+
outof: 6
9+
language: ja
10+
title: 環境、ユニバース、ミラー
11+
---
12+
13+
<span class="label important" style="float: right;">EXPERIMENTAL</span>
14+
15+
## 環境
16+
17+
リフレクションの環境は、リフレクションを用いたタスクが実行時に実行されたのかコンパイル時に実行されたのかによって変わる。
18+
この環境が実行時かコンパイル時かという違いは**ユニバース**と呼ばれるものによってカプセル化されている。
19+
リフレクション環境におけるもう 1つの重要なものにリフレクションを用いてアクセスが可能な実体の集合がある。
20+
この実体の集合は**ミラー**と呼ばれているものによって決定される。
21+
22+
例えば、実行時リフレクションによってアクセス可能な実体は `ClassloaderMirror` によって公開されている。
23+
このミラーは特定のクラスローダによって読み込まれた実体 (パッケージ、型、メンバ) のみへのアクセスを提供する。
24+
25+
ミラーはリフレクションを用いてアクセスすることができる実体の集合を決定するだけではなく、
26+
それらの実体に対するリフレクションを用いた演算を提供する。
27+
例えば、実行時リフレクションにおいて **invoker ミラー**を使うことで任意のクラスのメソッドやコンストラクタを呼び出すことができる。
28+
29+
## ユニバース
30+
31+
実行時とコンパイル時という 2つの主要なリフレクション機能があるため、ユニバースにも 2つのタイプがある。
32+
その時のタスクに応じて適切なユニバースを選ぶ必要がある。
33+
34+
- **実行時リフレクション** のためには `scala.reflect.runtime.universe`
35+
- **コンパイル時リフレクション**のためには `scala.reflect.macros.Universe`
36+
37+
を選ぶ。
38+
39+
ユニバースは、型 (`Type`)、構文木 (`Tree`)、アノテーション (`Annotation`)
40+
といったリフレクションで使われる主要な概念に対するインターフェイスを提供する。
41+
42+
## ミラー
43+
44+
リフレクションによって提供される全ての情報は**ミラー** (mirror) を通して公開されている。
45+
型情報の種類やリフレクションを用いたタスクの種類によって異なるミラーを使う必要がある。
46+
**クラスローダミラー**を使うことで型情報やそのメンバを取得することができる。
47+
クラスローダミラーから、より特殊化された (最も広く使われている) **invoker ミラー**
48+
を取得してリフレクションを使ったメソッドやコンストラクタ呼び出しやフィールドへのアクセスを行うことができる。
49+
50+
要約すると:
51+
52+
- **クラスローダミラー** これらのミラーは (`staticClass`/`staticModule`/`staticPackage` メソッドを使って) 名前をシンボルへと翻訳する。
53+
- **invoker ミラー** これらのミラーは (`MethodMirror.apply``FieldMirror.get` といったメソッドを使って) リフレクションを用いた呼び出しを実装する。これらの invoker ミラーは最も広く使われているミラーだ。
54+
55+
### 実行時のミラー
56+
57+
実行時におけるミラーの作り方は `ru.runtimeMirror(<classloader>)` だ (ただし、`ru``scala.reflect.runtime.universe`)。
58+
59+
`scala.reflect.api.JavaMirrors#runtimeMirror` の戻り値は
60+
`scala.reflect.api.Mirrors#ReflectiveMirror` 型のクラスローダミラーで、名前 (`name`) からシンボル (`symbol`) を読み込むことができる。
61+
62+
クラスローダミラーから
63+
(`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` を含む)
64+
invoker ミラーを作成することができる。
65+
66+
以下に具体例を用いてこれら 2つのタイプのミラーがどう関わっているのかを説明する。
67+
68+
### ミラーの型とその用例
69+
70+
`ReflectiveMirror` は名前を用いてシンボルを読み込むのと、invoker ミラーを作るのに使われる。作り方: `val m = ru.runtimeMirror(<classloader>)`
71+
具体例:
72+
73+
scala> val ru = scala.reflect.runtime.universe
74+
ru: scala.reflect.api.JavaUniverse = ...
75+
76+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
77+
m: reflect.runtime.universe.Mirror = JavaMirror ...
78+
79+
`InstanceMirror` はメソッド、フィールド、内部クラス、および内部オブジェクトの invoker ミラーを作成するのに使われる。作り方: `val im = m.reflect(<value>)`
80+
具体例:
81+
82+
scala> class C { def x = 2 }
83+
defined class C
84+
85+
scala> val im = m.reflect(new C)
86+
im: reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
87+
88+
`MethodMirror` はインスタンス・メソッド (Scala にはインスタンス・メソッドのみがある。オブジェクトのメソッドは `ModuleMirror.instance` から取得されるオブジェクト・インスタンスのインスタンス・メソッドだ。) の呼び出しに使われる。作り方: `val mm = im.reflectMethod(<method symbol>)`
89+
具体例:
90+
91+
scala> val methodX = ru.typeOf[C].declaration(ru.newTermName("x")).asMethod
92+
methodX: reflect.runtime.universe.MethodSymbol = method x
93+
94+
scala> val mm = im.reflectMethod(methodX)
95+
mm: reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e)
96+
97+
scala> mm()
98+
res0: Any = 2
99+
100+
`FieldMirror` はインスタンス・フィールドの get と set を行うのに使われる (メソッド同様に Scala はインスタンス・フィールドのみがある。)。作り方: `val fm = im.reflectMethod(<field or accessor symbol>)`
101+
具体例:
102+
103+
scala> class C { val x = 2; var y = 3 }
104+
defined class C
105+
106+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
107+
m: reflect.runtime.universe.Mirror = JavaMirror ...
108+
109+
scala> val im = m.reflect(new C)
110+
im: reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1
111+
112+
scala> val fieldX = ru.typeOf[C].declaration(ru.newTermName("x")).asTerm.accessed.asTerm
113+
fieldX: reflect.runtime.universe.TermSymbol = value x
114+
115+
scala> val fmX = im.reflectField(fieldX)
116+
fmX: reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1)
117+
118+
scala> fmX.get
119+
res0: Any = 2
120+
121+
scala> fmX.set(3)
122+
scala.ScalaReflectionException: cannot set an immutable field x
123+
...
124+
125+
scala> val fieldY = ru.typeOf[C].declaration(ru.newTermName("y")).asTerm.accessed.asTerm
126+
fieldY: reflect.runtime.universe.TermSymbol = variable y
127+
128+
scala> val fmY = im.reflectField(fieldY)
129+
fmY: reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1)
130+
131+
scala> fmY.get
132+
res1: Any = 3
133+
134+
scala> fmY.set(4)
135+
136+
scala> fmY.get
137+
res2: Any = 4
138+
139+
`ClassMirror` はコンストラクタの invoker ミラーを作成するのに使われる。作り方: 静的クラスは `val cm1 = m.reflectClass(<class symbol>)`、内部クラスは `val mm2 = im.reflectClass(<module symbol>)`
140+
具体例:
141+
142+
scala> case class C(x: Int)
143+
defined class C
144+
145+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
146+
m: reflect.runtime.universe.Mirror = JavaMirror ...
147+
148+
scala> val classC = ru.typeOf[C].typeSymbol.asClass
149+
classC: reflect.runtime.universe.Symbol = class C
150+
151+
scala> val cm = m.reflectClass(classC)
152+
cm: reflect.runtime.universe.ClassMirror = class mirror for C (bound to null)
153+
154+
scala> val ctorC = ru.typeOf[C].declaration(ru.nme.CONSTRUCTOR).asMethod
155+
ctorC: reflect.runtime.universe.MethodSymbol = constructor C
156+
157+
scala> val ctorm = cm.reflectConstructor(ctorC)
158+
ctorm: reflect.runtime.universe.MethodMirror = constructor mirror for C.<init>(x: scala.Int): C (bound to null)
159+
160+
scala> ctorm(2)
161+
res0: Any = C(2)
162+
163+
`ModuleMirror` はシングルトン・オブジェクトのインスタンスにアクセスするのに使われる。作り方: 静的なオブジェクトは `val mm1 = m.reflectModule(<module symbol>)`、内部オブジェクトは `val mm2 = im.reflectModule(<module symbol>)`
164+
具体例:
165+
166+
scala> object C { def x = 2 }
167+
defined module C
168+
169+
scala> val m = ru.runtimeMirror(getClass.getClassLoader)
170+
m: reflect.runtime.universe.Mirror = JavaMirror ...
171+
172+
scala> val objectC = ru.typeOf[C.type].termSymbol.asModule
173+
objectC: reflect.runtime.universe.ModuleSymbol = object C
174+
175+
scala> val mm = m.reflectModule(objectC)
176+
mm: reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null)
177+
178+
scala> val obj = mm.instance
179+
obj: Any = C$@1005ec04
180+
181+
### コンパイル時ミラー
182+
183+
コンパイル時ミラーは名前からシンボルを読み込むクラスローダミラーだけが使われる。
184+
185+
クラスローダミラーは `scala.reflect.macros.Context#mirror` を用いて作る。
186+
クラスローダミラーを使う典型的なメソッドには `scala.reflect.api.Mirror#staticClass`
187+
`scala.reflect.api.Mirror#staticModule`
188+
そして `scala.reflect.api.Mirror#staticPackage` がある。具体例で説明すると:
189+
190+
import scala.reflect.macros.Context
191+
192+
case class Location(filename: String, line: Int, column: Int)
193+
194+
object Macros {
195+
def currentLocation: Location = macro impl
196+
197+
def impl(c: Context): c.Expr[Location] = {
198+
import c.universe._
199+
val pos = c.macroApplication.pos
200+
val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object
201+
c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column)))))
202+
}
203+
}
204+
205+
**注意**: 手動でシンボルを照会する代わりに他の高レベルな方法もある。例えば、文字列を使わなくてもよいため型安全な
206+
`typeOf[Location.type].termSymbol` (もしくは `ClassSymbol` が必要ならば `typeOf[Location].typeSymbol`) がある。

0 commit comments

Comments
 (0)
0