Edited at

The Go Blogの「The Laws of Reflection」を翻訳してみた

More than 1 year has passed since last update.


The Laws of Reflection(Reflectionの法則について)


Introduction(はじめに)

コンピューティングにおけるReflectionはプログラム自身が自分の構造(特に型について)を調査するための機能で、メタプログラミングの方式の一つです


Reflection in computing is the ability of a program to examine its own structure, particularly through types;

it's a form of metaprogramming. It's also a great source of confusion.


本記事はGoにおけるreflectionの動きを説明することによってメタプログラミングについて明らかにできるかを試みています。


In this article we attempt to clarify things by explaining how reflection works in Go.


他の言語のreflectionモデルは難しく、多くの言語ではすべてをサポートしていません。

しかし本記事はGoについて語るため、ひとまずここで言う"reflection"は”Goにおけるreflection”とします。


Each language's reflection model is different (and many languages don't support it at all), but this article is about Go, so for the rest of this article the word "reflection" should be taken to mean "reflection in Go".



Types and interfaces(型とインターフェース)

型システムの上で構築されたreflectionのため、

まずはGoにおける型について復習しましょう。


Because reflection builds on the type system, let's start with a refresher about types in Go.


Goでは静的型付けされており、全ての変数は静的な型を持ち、コンパイル時に確定しています。例えばint,float32, *MyType, []byte等


Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: int, float32, *MyType, []byte, and so on.


以下のように定義したとします


If we declare


type MyInt int

var i int
var j MyInt

この時、iはint型を持ちjはMyInt型を持ちます。

変数i,jはベースは同じ型だとしても別個の静的型であり、型変換なしに相互にアサインし直すことはできません。


then i has type int and j has type MyInt. The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.


interface型についての重要なこととして、

interface型はメソッド集合を保持しています。

1つのinterface型変数はそのinterface型と同様のメソッド集合を実装している(inteface型ではない)実態値を格納できます。


One important category of type is interface types, which represent fixed sets of methods. An interface variable can store any concrete (non-interface) value as long as that value implements the interface's methods.


よく知られている例としてioパッケージのio.Readerとio.Writerがあります。


A well-known pair of examples is io.Reader and io.Writer, the types Reader and Writer from the io package:


// ReaderはReadメソッドだけを持ちます

// Reader is the interface that wraps the basic Read method.
type Reader interface {
Read(p []byte) (n int, err error)
}

// Writerはwriteメソッドだけを持ちます
// Writer is the interface that wraps the basic Write method.
type Writer interface {
Write(p []byte) (n int, err error)
}

ある型がReadメソッド(もしくはWriteメソッド)を実装することは、

io.Reader(もしくはio.Writer)を実装したことを意味します。


Any type that implements a Read (or Write) method with this signature is said to implement io.Reader (or io.Writer).


つまりまとめると、io.ReaderはReadメソッドを持つどんな型も保持することができるのです。


For the purposes of this discussion, that means that a variable of type io.Reader can hold any value whose type has a Read method:


var r io.Reader

r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)
// and so on

重要なのは、上記コードのrの型は様々な実態値を保持することができますが、rは常にio.Reader型であるということ:Goは静的型言語でありrはio.Reader型の静的型であるということです。


It's important to be clear that whatever concrete value r may hold, r's type is always io.Reader: Go is statically typed and the static type of r is io.Reader.


極めて重要な例として空interface型があります。


An extremely important example of an interface type is the empty interface:


interface{}

これはメソッドを持たないことを意味し

あらゆる値(メソッドを持たなかろうといくつ持とうと関係なく)を保持することができます。


It represents the empty set of methods and is satisfied by any value at all, since any value has zero or more methods.


人はGoのinterfaceは動的型と言うでしょう。

しかしそれはミスリードです。

それらは静的型なのです。


Some people say that Go's interfaces are dynamically typed, but that is misleading. They are statically typed:


interface型の変数は、常に同じ静的型があり、実行時にinterface変数に格納された値の型を変更しても、その値は常にinterfaceを満たします。


a variable of interface type always has the same static type, and even though at run time the value stored in the interface variable may change type, that value will always satisfy the interface.


reflectionとinterfaceはかなり近しい関連があるため、正確に理解する必要がありました。


We need to be precise about all this because reflection and interfaces are closely related.



The representation of an interface(interfaceの表現)

Russ CoxはGoにおけるinterfaceの表現についてブログにポストしています。


Russ Cox has written a detailed blog post about the representation of interface values in Go.


全てをここで繰り返し説明するのは簡単ではないので、シンプルに要点だけをまとます。


It's not necessary to repeat the full story here, but a simplified summary is in order.


interface型変数は実態値、型記述子を保持しています


A variable of interface type stores a pair: the concrete value assigned to the variable, and that value's type descriptor.


具体的には、値がinterfaceを実装している下位の具体的なデータ項目であり、タイプには、その項目の完全なタイプを説明しています。例えば


To be more precise, the value is the underlying concrete data item that implements the interface and the type describes the full type of that item. For instance, after


var r io.Reader

tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
return nil, err
}
r = tty

rはわかりやすく言えば、値と型のペアを持ち、値:tty,型:*os.Fileとなります。

注意点として、*os.File型はRead以外の他のメソッドも実装しinterface値はReadメソッドへのアクセスだけを提供しているに過ぎず、内部的にはその値の全ての型情報が運ばれます。

だからこそ以下のようなことが可能なのです。


r contains, schematically, the (value, type) pair, (tty, *os.File). Notice that the type *os.File implements methods other than Read; even though the interface value provides access only to the Read method, the value inside carries all the type information about that value. That's why we can do things like this:


var w io.Writer

w = r.(io.Writer)

上記構文が型アサーションです。

アサートすると、rの内側のアイテムもio.Writerを実装しているので、wに割り当てることができます。割当て後、wtty,*os.Fileが含まれます。

つまり、rで保持していたものと同じペアです。


The expression in this assignment is a type assertion; what it asserts is that the item inside r also implements io.Writer, and so we can assign it to w. After the assignment, w will contain the pair (tty, *os.File). That's the same pair as was held in r.


静的なinterface型は、内部での具体的な値がメソッドの大きなセットを持っている場合でも、interface変数に沿ったメソッド呼び出しを決定します。


The static type of the interface determines what methods may be invoked with an interface variable, even though the concrete value inside may have a larger set of methods.


続けて以下のようにコードを追加します


Continuing, we can do this:


var empty interface{}

empty = w

空のinterface値は再び、tty,*os.Fileのペアを保持します。

空のインターフェイスは、便利なことに、任意の値を保持することができますし、私たちが値について必要とすることができるすべての情報が含まれています。


and our empty interface value empty will again contain that same pair, (tty, *os.File). That's handy: an empty interface can hold any value and contains all the information we could ever need about that value.


(wは空interfaceという条件を静的に満たすので、ここで型アサーションは必要ありません。

ReaderからWriterに値を移動する例では、WriterのメソッドがReaderのサブセットではないので、型アサーションを使用し明示化する必要がありました。)


(We don't need a type assertion here because it's known statically that w satisfies the empty interface. In the example where we moved a value from a Reader to a Writer, we needed to be explicit and use a type assertion because Writer's methods are not a subset of Reader's.)


一つ重要な詳細情報としてがinteface内部のペアは、常に(値、具体的な型)の形態があり、(値、interface型)の形態を持つことができないということです。


One important detail is that the pair inside an interface always has the form (value, concrete type) and cannot have the form (value, interface type). Interfaces do not hold interface values.


さぁ、reflectについて学ぶ準備が揃いました。


Now we're ready to reflect.



The first law of reflection(reflection第一の法則)


  1. Reflectionは、interface値からreflectionオブジェクトに変換できる。



  1. Reflection goes from interface value to reflection object.


基本レベルでは、reflectionがインターフェース変数内に格納されている型と値のペアを検討するだけのメカニズムです。


At the basic level, reflection is just a mechanism to examine the type and value pair stored inside an interface variable.


初めにreflectパッケージには2つの型があることを知っておく必要があります。

TypeValueです。


To get started, there are two types we need to know about in package reflect: Type and Value.


これら二つの型がinterface変数の内容に対するアクセスを提供します。

そして2つのシンプルな関数reflect.TypeOfとreflect.ValueOfを呼び出すことでinterface値からreflect.Typeとreflect.Valueを取り出します。


Those two types give access to the contents of an interface variable, and two simple functions, called reflect.TypeOf and reflect.ValueOf, retrieve reflect.Type and reflect.Value pieces out of an interface value.


(reflect.Valueからreflect.Typeを取得するのは簡単ですが、まずは今はValue、Typeの概念は分離して考えましょう。)


(Also, from the reflect.Value it's easy to get to the reflect.Type, but let's keep the Value and Type concepts separate for now.)


TypeOfから始めましょう


Let's start with TypeOf:


package main

import (
"fmt"
"reflect"
)

func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}

このプログラムの出力は、


This program prints


type: float64

reflect.TypeOfに、interface値ではなく、float64の変数xを渡しているようにプログラム上見えるので、不思議に思われるかもしれません。


You might be wondering where the interface is here, since the program looks like it's passing the float64 variable x, not an interface value, to reflect.TypeOf.


しかし、以下にgodocへの抜粋を示しますが、reflect.TypeOfは空interfaceを引数にとっています。


But it's there; as godoc reports, the signature of reflect.TypeOf includes an empty interface:


// TypeOf returns the reflection Type of the value in the interface{}.

func TypeOf(i interface{}) Type

reflect.TypeOf(x)を呼び出した際、

xは空interfaceに格納されます。

reflect.TypeOf(X)を呼び出すと、xが最初に空interfaceに格納され引数として渡されます。reflect.TypeOfは空interfaceをアンパックし型情報を復元します。


When we call reflect.TypeOf(x), x is first stored in an empty interface, which is then passed as the argument; reflect.TypeOf unpacks that empty interface to recover the type information.


reflect.ValueOf関数ももちろん、値を復元します。

(定型文を省き実行可能なコードに焦点を当てます)


The reflect.ValueOf function, of course, recovers the value (from here on we'll elide the boilerplate and focus just on the executable code):


var x float64 = 3.4

fmt.Println("value:", reflect.ValueOf(x))

出力は以下


prints


value: <float64 Value>

reflect.Typeとreflect.Valueの両方が値を検査し操作できるようにするメソッドが多数あります。一つの重要な例として、Valueはreflect.ValueからType型を返すTypeメソッドを持っているということです。


Both reflect.Type and reflect.Value have lots of methods to let us examine and manipulate them. One important example is that Value has a Type method that returns the Type of a reflect.Value.


もう一つの重要点としてTypeとValueの両方がKindメソッドをもっており、Uint、Float64、Slice、等を示す定数を返します


Another is that both Type and Value have a Kind method that returns a constant indicating what sort of item is stored: Uint, Float64, Slice, and so on.


また、ValueのIntやFloatのような名前のメソッドによって、内部に格納されている値の取得ができます。


Also methods on Value with names like Int and Float let us grab values (as int64 and float64) stored inside:



var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())

出力


prints


type: float64

kind is float64: true
value: 3.4

SetIntとSetFloatのようなメソッドもありますが、使うにはsettabilityに対する理解が必要で、Reflectionの3番目の法則で述べます。


There are also methods like SetInt and SetFloat but to use them we need to understand settability, the subject of the third law of reflection, discussed below.


reflectionライブラリのいくつかの特性について説明します。まず、一つ目はシンプルなAPIを維持するために、Valueの「getter」「setter」メソッドは値を保持できる最大のタイプを操作します。

例:int64型のすべての符号付き整数つまり、価値のInt Methodはint64型を返し、SetInt値はint64型をとります。あとで実際の型に変換する必要があるかもしれないです。


The reflection library has a couple of properties worth singling out. First, to keep the API simple, the "getter" and "setter" methods of Value operate on the largest type that can hold the value: int64 for all the signed integers, for instance. That is, the Int method of Value returns an int64 and the SetInt value takes an int64; it may be necessary to convert to the actual type involved:


var x uint8 = 'x'

v := reflect.ValueOf(x)
fmt.Println("type:", v.Type()) // uint8.
fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
x = uint8(v.Uint()) // v.Uint returns a uint64.

2つ目の特性として、reflectionオブジェクトのKindは、静的型ではなく、基底型を記述していることです。


The second property is that the Kind of a reflection object describes the underlying type, not the static type.


以下のように、reflectionオブジェクトに、ユーザー定義の整数型の値が含まれている場合


If a reflection object contains a value of a user-defined integer type, as in


type MyInt int

var x MyInt = 7
v := reflect.ValueOf(x)

vのKindは、xの静的型がintではなくMyIntでも、reflect.Intのままとなります。


the Kind of v is still reflect.Int, even though the static type of x is MyInt, not int.


言い換えれば、KindはMyIntからint型を区別することはできません。(Typeは可能です。)


In other words, the Kind cannot discriminate an int from a MyInt even though the Type can.



The second law of reflection(reflection第二の法則)

2.Reflectionは、reflectionオブジェクトからinterface値に変換できる。


2.Reflection goes from reflection object to interface value.


物理的な反射のように、GoにおけるReflectionは、独自の反転物をつくります。


Like physical reflection, reflection in Go generates its own inverse.


reflect.ValueのInterfaceメソッドを使うことで、interface値を回復することができます;interfaceの表現に戻す型と値の情報をパックし、結果を返します


Given a reflect.Value we can recover an interface value using the Interface method; in effect the method packs the type and value information back into an interface representation and returns the result:


// Interface はvの値をinterface{}として返す。

func (v Value) Interface() interface{}

結果として、我々は言うことができる


As a consequence we can say


y := v.Interface().(float64) // y will have type float64.

fmt.Println(y)

reflectionオブジェクトvで表されるfloat64値を出力します。


to print the float64 value represented by the reflection object v.


fmt.Println、fmt.Printfへの引数は、すべて空interface値として渡され前の例と同様、fmtパッケージの内部でアンパックされます


We can do even better, though. The arguments to fmt.Println, fmt.Printf and so on are all passed as empty interface values, which are then unpacked by the fmt package internally just as we have been doing in the previous examples.


従って、正しくreflect.Valueの内容を印刷するためにInterfaceメソッドの結果をフォーマットされた印刷ルーチンに渡します


Therefore all it takes to print the contents of a reflect.Value correctly is to pass the result of the Interface method to the formatted print routine:


fmt.Println(v.Interface())

(なぜ fmt.Println(v)じゃないのか。vはreflect.Valueに過ぎず、本当に欲しいのは保持していいる実態値だからです)

値はfloat64型なので、望むなら浮動小数点フォーマットを使えます:


(Why not fmt.Println(v)? Because v is a reflect.Value; we want the concrete value it holds.) Since our value is a float64, we can even use a floating-point format if we want:


fmt.Printf("value is %7.1e\n", v.Interface())

この場合は以下となります


and get in this case


3.4e+00

繰り返しですが、v.Interface()の結果をfloat64へアサートする必要はありません。空interfaceの値が内部の具体的な値の型情報を持ち、Printfはそれを回復します。


Again, there's no need to type-assert the result of v.Interface() to float64; the empty interface value has the concrete value's type information inside and Printf will recover it.


一言で言えば、Interfaceメソッドは、valueOf関数の逆関数です。常にその結果は静的型interface{}であることという点は異なりますが


In short, the Interface method is the inverse of the ValueOf function, except that its result is always of static type interface{}.


まとめますと、Reflectionはinterface値からreflectionオブジェクトに変換でき、逆変換も可能です。


Reiterating: Reflection goes from interface values to reflection objects and back again.



The third law of reflection(reflection第三の法則)

3.reflectionオブジェクトを変更するには、値は設定可能でなければなりません。


3.To modify a reflection object, the value must be settable.


第三法則は、最も微妙で分かりにくいですが、最初の原理から順に進めれば十分理解できるはずです。


The third law is the most subtle and confusing, but it's easy enough to understand if we start from first principles.


ここに動作しないコードがありますが、勉強する価値があります。


Here is some code that does not work, but is worth studying.


var x float64 = 3.4

v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.

このコードを実行すると、それは不可解なメッセージを表示してパニックになるでしょう


If you run this code, it will panic with the cryptic message


panic: reflect.Value.SetFloat using unaddressable value

問題は、値7.1はアドレス可能ではないことではありません。vが設定可能ではないことです。Settabilitiyは、reflection Valueのプロパティですべてのreflection Valueがそれを持っているわけではないのです。


The problem is not that the value 7.1 is not addressable; it's that v is not settable. Settability is a property of a reflection Value, and not all reflection Values have it.


ValueのCanSetメソッドは、値のSettabilityを取得します。例を見てみましょう。


The CanSet method of Value reports the settability of a Value; in our case,


var x float64 = 3.4

v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())

出力


prints


settability of v: false

上記の様に、設定不可な値にSetメソッドを呼び出すとエラーになります。しかし、Settabilityとは何でしょうか?


It is an error to call a Set method on an non-settable Value. But what is settability?


Settabilitiyは少しアドレス可能が、より厳格なようなものです。それは、reflectionオブジェクトがreflectionオブジェクトの作成に使用された実記憶を変更できるプロパティです。Settabilitiyは、reflectionオブジェクトが元のアイテムを保持しているか否かによって決定されます。


Settability is a bit like addressability, but stricter. It's the property that a reflection object can modify the actual storage that was used to create the reflection object. Settability is determined by whether the reflection object holds the original item. When we say


var x float64 = 3.4

v := reflect.ValueOf(x)

私たちはreflect.ValueOfにxのコピーを渡すので、reflect.ValueOfの引数として作成されたinterfaceの値は、x自身でなくxのコピーです。下記のコードについて


we pass a copy of x to reflect.ValueOf, so the interface value created as the argument to reflect.ValueOf is a copy of x, not x itself. Thus, if the statement


v.SetFloat(7.1)

もし処理が成功しても、vがxから作成されたように見えても、xは更新されないでしょう


were allowed to succeed, it would not update x, even though v looks like it was created from x.


代わりに、reflection value内に格納されたxのコピーを更新し、x自身が影響しません。これは混乱を招き、役に立たないので、不正としました。

Settabilityは、この問題を回避するために使用されるプロパティです。


Instead, it would update the copy of x stored inside the reflection value and x itself would be unaffected. That would be confusing and useless, so it is illegal, and settability is the property used to avoid this issue.


奇妙なようですが、そうではありません。これは、実際に異常な挙動においてお馴染みの状況です。関数にxを渡すことを考えてください


If this seems bizarre, it's not. It's actually a familiar situation in unusual garb. Think of passing x to a function:


f(x)

x自身でなく、xの値のコピーを渡されたので、fはxを修正することができるように期待できません、xを変更する場合、直接関数fにxのアドレスを渡す必要があります(つまりxのポインタです)


We would not expect f to be able to modify x because we passed a copy of x's value, not x itself. If we want f to modify x directly we must pass our function the address of x (that is, a pointer to x):


f(&x)

これは簡単でよく知られています。そしてreflectionが同じように動作します。つまり、reflectionによりxを変更したい場合は、reflectionライブラリに修正したい値へのポインタを与える必要があります。


This is straightforward and familiar, and reflection works the same way. If we want to modify x by reflection, we must give the reflection library a pointer to the value we want to modify.


やってみましょう。まず私たちはいつものようにxを初期化し、pというreflection valueを作成してみます。


Let's do that. First we initialize x as usual and then create a reflection value that points to it, called p.


var x float64 = 3.4

p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

出力は


The output so far is


type of p: *float64

settability of p: false

reflectionオブジェクトpが設定可能ではありませんが、それは私たちが設定したいpでははありません、必要なのは*pです。 私たちはポインタを介してインダイレクトValueのElemのメソッドを呼び出し結果を取得、reflection value vで結果を保存します


The reflection object p isn't settable, but it's not p we want to set, it's (in effect) *p. To get to what p points to, we call the Elem method of Value, which indirects through the pointer, and save the result in a reflection Value called v:


v := p.Elem()

fmt.Println("settability of v:", v.CanSet())

出力結果が示すようにvは設定可能なreflection objectです。


Now v is a settable reflection object, as the output demonstrates,


settability of v: true

それは、xを表しているため、私たちは最終的にxの値を変更するためにv.SetFloatを使用することができます:


and since it represents x, we are finally able to use v.SetFloat to modify the value of x:


v.SetFloat(7.1)

fmt.Println(v.Interface())
fmt.Println(x)

出力は期待通りです


The output, as expected, is


7.1

7.1

Reflectionを理解するのは難しいことですが、reflectionTypeとValueを経てではありますが、言語が何を正確に何をやっているそれは何が起こっているのか明らかにできます。ただreflection Valueは、何を表しているか、変更するために、アドレスを必要とすることに注意してください。


Reflection can be hard to understand but it's doing exactly what the language does, albeit through reflection Types and Values that can disguise what's going on. Just keep in mind that reflection Values need the address of something in order to modify what they represent.



Structs(構造体)

前の例 vはポインタそのものではありませんでしたが、ポインタから誘導された値でした。構造体のフィールドを変更するためにreflectionを使用する場合、この状況が発生する共通の方法になります。構造体はアドレスを持っているように、そのフィールドを変更できます。


In our previous example v wasn't a pointer itself, it was just derived from one. A common way for this situation to arise is when using reflection to modify the fields of a structure. As long as we have the address of the structure, we can modify its fields.


ここでは構造体の値、tは分析する簡単な例を示します。私たちは、後でそれを変更したいと思うので、私たちは、構造体のアドレスをreflectionオブジェクトを作成します。その後、私たちはその型にtypeOfTを設定し、簡単なメソッド呼び出しを使用してフィールドを反復処理します(詳細はreflectパッケージを参照してください)。

構造体型からフィールドの名前を抽出しますが、フィールド自体は正規のreflect.Valueオブジェクトであることに注意してください。


Here's a simple example that analyzes a struct value, t. We create the reflection object with the address of the struct because we'll want to modify it later. Then we set typeOfT to its type and iterate over the fields using straightforward method calls (see package reflect for details). Note that we extract the names of the fields from the struct type, but the fields themselves are regular reflect.Value objects.


type T struct {

A int
B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
fmt.Printf("%d: %s %s = %v\n", i,
typeOfT.Field(i).Name, f.Type(), f.Interface())
}

このプログラムの出力は


The output of this program is


0: A int = 23

1: B string = skidoo

ここで導入されたSettabilityについてのもう一つのポイントがあります。

Tのフィールド名は、構造体のエクスポートされたフィールドのみが設定可能であるため、(エクスポートするために)UpperCaseにします。


There's one more point about settability introduced in passing here: the field names of T are upper case (exported) because only exported fields of a struct are settable.


sに設定可能なreflectionオブジェクトが含まれているため、私たちは構造体のフィールドを変更することができます。


Because s contains a settable reflection object, we can modify the fields of the structure.


s.Field(0).SetInt(77)

s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)

結果は

And here's the result:

t is now {77 Sunset Strip}

sが&tではなくtから作成されたものとして、プログラムを変更した場合、tのフィールドは設定可能ではないとして、SetIntメソッドとsetStringの呼び出しは失敗します。


If we modified the program so that s was created from t, not &t, the calls to SetInt and SetString would fail as the fields of t would not be settable.



Conclusion(結論)

再びreflectionの法則をまとめます


Here again are the laws of reflection:


Reflectionは、interface値からreflectionオブジェクトに変換する。

Reflectionは、reflectionオブジェクトからinterface値に変換する。

reflectionオブジェクトを変更するには、値は設定可能でなければなりません。

GoにおけるこれらのReflectionの法則を理解すれば、はるかに使いやすくなります。それは注意して使用し、厳密には必要でない限り避けるべきですが、強力なツールです。


Reflection goes from interface value to reflection object.

Reflection goes from reflection object to interface value.

To modify a reflection object, the value must be settable.

Once you understand these laws reflection in Go becomes much easier to use, although it remains subtle. It's a powerful tool that should be used with care and avoided unless strictly necessary.


reflectionについてカバーされていないこと

--送信と受信チャンネルで、メモリの割り当て、スライスとマップを使用、メソッドや関数を呼び出す-- はあるが、この記事はもう十分な長さです。

私たちは、後の記事でこれらのトピックのいくつかを取り上げます。


There's plenty more to reflection that we haven't covered — sending and receiving on channels, allocating memory, using slices and maps, calling methods and functions — but this post is long enough. We'll cover some of those topics in a later article.


By Rob Pike