ぺい

大阪の専門学生の落書き。主にエンジニア寄りの話。

Golangのreflectの公式ドキュメント翻訳

reflectパッケージ

f:id:tikasan0804:20170719172956p:plain

※翻訳については、ざっくりこんな感じくらいのノリです。

reflect - The Go Programming Language

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.

Package reflectionは実行時reflectionを実装し、プログラムが任意の型のオブジェクトを操作できるようにします。 一般的な使用方法は、静的型interface{}で値をとり、Typeを返すことで動的型情報を抽出することです。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println("----typeof-----")
    typeof(1, "string", true)
    fmt.Println("----typeof2-----")
    typeof2(1)
}

// vが何の値かを出力する
func typeof(value ...interface{}) {
    for _, v := range value {
        fmt.Println(reflect.TypeOf(v))
    }
}

// vがint型と同じか比較する
func typeof2(v interface{}) {
    fmt.Println(reflect.TypeOf(v).Kind() == reflect.Int)
}
go run intro1/main.go
----typeof-----
int
string
bool
----typeof2-----
true

A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.

ValueOfを呼び出すと、実行時データを表すValueが返されます。 ZeroはTypeを取り、その型のゼロ値を表すValueを返します。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    fmt.Println("----valueof-----")
    valueof(1, "str", false)
    fmt.Println("----valueof2-----")
    valueof2(100)
    fmt.Println("----valueof3-----")
    valueof3()
}

// vからValueOfでポインタにアクセスして、Elemでポインタにある値を返す
func valueof(value ...interface{}) {
    for _, v := range value {
        fmt.Println(reflect.ValueOf(&v).Elem())
    }
}

// valueに格納されている値がint型と適合したら、その値をansに格納する
func valueof2(value interface{}) {
    var ans int
    v := reflect.ValueOf(&value).Elem()
    if intValue, ok := v.Interface().(int); ok {
        ans += intValue
        fmt.Println(ans)
    }
}

// int型のゼロ値を取得し表示する
func valueof3() {
    var value int
    fmt.Println(reflect.ValueOf(&value).Elem())
}
go run intro2/main.go
----valueof-----
1
str
false
----valueof2-----
100
----valueof3-----
0

See “The Laws of Reflection” for an introduction to reflection in Go: https://golang.org/doc/articles/laws_of_reflection.html

Goでのreflectionの概要については、「The Laws of Reflection」を参照してください。https://golang.org/doc/articles/laws_of_reflection.html

リフレクションの法則

The Laws of 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.

コンピューティングにおけるリフレクションとは、プログラムが自分の構造、特に型を調べる能力です。 それはメタプログラミングの一種です。 それはまた混乱の大きな原因です。

In this article we attempt to clarify things by explaining how reflection works in Go. 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”.

この記事では、Goでreflectionがどのように機能するかを説明して、物事を明確にしようとしています。 各言語のreflection modelは異なっていますが(そして多くの言語ではそれをサポートしていません)。これはGoについての記事なので、「reflection」という言葉は「Goのreflection」を意味すると解釈されるべきです

前書き

Introduction

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

reflectionはシステム上に構築されるため、Goのタイプについての再考から始めましょう。

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

Goは静的に型付けされています。 すべての変数は静的型を持ちます。つまり、int、float32、* MyType、 byteなど、コンパイル時に既知で固定された1つの型だけです。
もし、変数宣言をしたら以下のようになります。

type MyInt int

var i int
var j MyInt

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.

MyIntはint型を持ち、jはMyInt型を持っています。 変数iとjには別個の静的型があり、それらは同じ基底型を持ちますが、変換なしでは互いに割り当てることはできません。

i = j // 同じ基底クラスのintをもっていても代入出来ない。

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. A well-known pair of examples is io.Reader and io.Writer, the types Reader and Writer from the io package:

typeの重要なカテゴリの1つは、固定されたメソッドセットを表すinterface typesです。 interface変数は、その値がinterfaceのメソッドを実装している限り、任意の具体的な(非interface)値を格納できます。
よく知られた例のペアは、io.Readerとio.Writerです。これは、ioパッケージのReaderとWriterタイプです。interfaceについては、Javaなどにあるものと同じような挙動をします。

// Readerは、基本的なReadメソッドをラップするinterfaceです。
type Reader interface {
    Read(p []byte) (n int, err error)
}

// Writerは、基本的なWriteメソッドをラップするinterfaceです。
type Writer interface {
    Write(p []byte) (n int, err error)
}

Any type that implements a Read (or Write) method with this signature is said to implement io.Reader (or io.Writer). 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:

このシグネチャでRead(またはWrite)メソッドを実装するすべての型は、io.Reader(またはio.Writer)を実装すると言われています。 ここでは、io.Reader型の変数に、その型がReadメソッドを持つ値を保持できることを示します。

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

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.

どのような具体的な値rが保持されていても、rの型は常にio.Readerです:Goは静的に型指定され、静的型はio.Readerです。

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.

これは、空のメソッドセットを表し、任意の値が0以上のメソッドを持つため、すべての値がすべて満たされます。

Some people say that Go’s interfaces are dynamically typed, but that is misleading. They are statically typed: 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.

一部の人々は、Goのinterfaceは動的に型付けされていると言いますが、それは誤解を招くものです。 それらは静的に型付けされています:interface型の変数は常に同じ静的型を持ち、実行時にinterface変数に格納された値が型を変更しても、その値は常にinterfaceを満たします。

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

reflectionとinterfacesは密接に関連しているため、すべてのことについて正確にする必要があります。

インタフェースの表現

The representation of an 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.

Russ Coxは、Goにinterfaceの値を表現するための詳細なブログ記事を書いています。 ここでは話を繰り返す必要はないですが、簡略な要約が必要です。

A variable of interface type stores a pair: the concrete value assigned to the variable, and that value’s type descriptor. 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

interface typeの変数は、変数に割り当てられた具体的な値と、その値のタイプ記述子のペアを格納します。 より正確に言えば、値はinterfaceを実装する基礎となる具体的なデータ項目であり、タイプはその項目のフルタイプを表します。

例えば

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

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:

rには (value, type) の対(tty, os.File)が概略的に含まれています。 os.File型はRead以外のメソッドを実装していることに注意してください。 interface値がReadメソッドへのアクセスのみを提供しても、内部の値はその値に関するすべての型情報を保持します。 だから私たちはこのようなことをすることができます。

var w io.Writer
w = r.(io.Writer)

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. 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.

この代入の式は型アサーションです。 それが主張するのは、rの中のアイテムもio.Writerを実装しているので、wに割り当てることができるということです。 代入の後、wにはペア(tty, *os.File)が含まれます。 それはrと同じペアです。 インタフェースの静的型は、内部の具体的な値がより大きな一連のメソッドを持つ場合でも、インタフェース変数で呼び出されるメソッドを決定します。

Continuing, we can do this:

続けて、これを行うことが出来ます。

var empty interface{}
empty = w

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.

空のinterfaceの空の値には、同じペア (tty, *os.File)が再び含まれます。 それは便利です:空のinterfaceは、任意の値を保持することができ、我々がその値について必要とする可能性のあるすべての情報を含みます。

(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.)

ここでは、wが空のinterfaceを満たしていることが静的にわかっているため、タイプアサーションは必要ありません。ReaderからWriterに値を移動した例では、明示的に型アサーションを使用する必要がありました。 Readerのサブセットではありません)。

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.

1つの重要な詳細は、interface内のペアは常にフォーム(値、具体的なタイプ)を持ち、フォーム(値、interface型)を持つことができないということです。interfaceはinterface値を保持しません。

Now we’re ready to reflect.

今我々は反映する準備が整いました。

reflectionの第1の法則

The first law of reflection

1.Reflectionは、interface値からreflection objectに向かう

  1. Reflection goes from interface value to reflection object.

At the basic level, reflection is just a mechanism to examine the type and value pair stored inside an interface variable. To get started, there are two types we need to know about in package reflect: Type and 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. (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.)

基本レベルでは、reflectionはinterface変数の内部に格納されている型と値のペアを調べるメカニズムに過ぎません。 始めるには、パッケージreflectに反映させるためにTypeValueの2種類が必要です。 これらの2つの型は、interface変数の内容にアクセスできます。また、reflect.TypeOfおよびreflect.ValueOfという2つの単純な関数は、reflect.Typeとreflectを取得します。 (また、reflect.Valueからreflect.Typeに到達するのは簡単ですが、ValueとTypeのコンセプトを今のところ分けておきましょう。)

Let’s start with TypeOf:

TypeOfから始めましょう。

package main

import (
    "fmt"
    "reflect"
)

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

This program prints

このプログラムをプリントすると

type: float64

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. But it’s there; as godoc reports, the signature of reflect.TypeOf includes an empty interface:

interfaceの値ではなくfloat64変数xを渡しているように見えるので、interfaceがどこにあるのか疑問に思うかもしれません。 しかしそれはreflect.TypeOfにあります。 godocレポートとして、reflect.TypeOfのシグネチャには空のinterfaceが含まれています。

// TypeOfは、インタフェース{}内の値のreflection Typeを返します。
func TypeOf(i interface{}) Type

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.TypeOf(x)を呼び出すと、xはまず空のinterfaceに格納され、引数として渡されます。 型情報を復元するために空のinterfaceを展開します。

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

もちろんreflect.ValueOf関数は値を復元します(ここからは、ボイラープレートを削除し、実行可能コードだけに焦点を当てます)。

var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x).String())

prints

value: <float64 Value>

(We call the String method explicitly because by default the fmt package digs into a reflect.Value to show the concrete value inside. The String method does not.)

(デフォルトでは、fmtパッケージはreflect.Valueを掘り下げて具体的な値を内部に表示するため、Stringメソッドは明示的に呼び出します。Stringメソッドはそうではありません)。 ちなみに、これをStringなしで実行すると

var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x))
value: 3.4

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. 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. Also methods on Value with names like Int and Float let us grab values (as int64 and float64) stored inside:

どちらも反映されます。 reflect.Typeとreflect.Valueには、それらを調べて操作するための方法がたくさんあります。 1つの重要な例として、ValueはTypeはreflect.ValueのTypeを返すメソッド があります。 もう一つは、TypeとValueの両方に、どの種類のアイテムが格納されているかを示す定数(Uint、Float64、Sliceなど)を返すKindメソッドがあることです。 また、IntやFloatのような名前を持つValueのメソッドでは、内部に格納されている値(int64とfloat64など)を取得できます。

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

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.

SetIntやSetFloatのようなメソッドもありますが、それらを使用するには、後述する第3回reflectionの主題である設定可能性を理解する必要があります。

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:

reflectionライブラリには、注目に値するいくつかのプロパティがあります。 まず、APIを単純なものにするために、Valueのgetterメソッドとsetterメソッドは、値を保持できる最大の型、たとえば、すべての符号付き整数に対してint64で動作します。 つまり、ValueのIntメソッドはint64を返し、SetInt値はint64を返します。 関係する実際のタイプに変換する必要があるかもしれません:

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.

The second property is that the Kind of a reflection object describes the underlying type, not the static type. If a reflection object contains a value of a user-defined integer type, as in

2番目のプロパティは、reflection objectの種類が静的型ではなく基底型を記述していることです。 reflection objectにユーザ定義の整数型の値が含まれている場合

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

the Kind of v is still reflect.Int, even though the static type of x is MyInt, not int. In other words, the Kind cannot discriminate an int from a MyInt even though the Type can.

静的な型のxはintではなくMyIntであるにもかかわらず、vの種類はまだ reflect.Intです。 言い換えれば、種類はできますが、KindはMyIntからintを区別できません。

reflectionの第2の法則

The second law of reflection

Reflectionはreflection objectからinterfaceの値に向かう

  1. Reflection goes from reflection object to interface value.

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

物理的な反射のように、Goでのreflectionはそれ自身の逆を生成します。

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:

与えられたreflect.Valueは、Interfaceメソッドを使用してInterface値を復元できます。 実際にはこのメソッドは型と値の情報をInterface表現にパックして返します。

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

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

reflection object vによって表されるfloat64値を出力する。

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. 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、fmt.Printfなどの引数は、すべて空のinterface値として渡され、前の例で行ったように内部的にfmtパッケージによってアンパックされます。 したがって、reflect.Valueの内容を出力するには、Interfaceメソッドの結果を書式付きprintルーチンに渡すだけです。

fmt.Println(v.Interface())

(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.Println(v)なのか?vはreflect.Valueなので、具体的な値が必要です。)値がfloat64なので、必要ならば浮動小数点フォーマットを使用することもできます:

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

and get in this case

この場合

3.4e+00

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.

ここでも、v.Interface()の結果をfloat64にタイプアサートする必要はありません。 空のinterfaceの値は具体的な値の型情報を内部に持ち、Printfはそれを復元します。

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

要するに、InterfaceメソッドはValueOf関数の逆ですが、その結果は常に静的型interface{}である点が異なります。

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

繰り返します:Reflectionはinterface値からreflection objectsに戻り、再び戻る。

reflectionの第3の法則

The third law of reflection

3.reflection objectを変更するには、その値を設定可能にする必要があります。

  1. 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.

第3の法則は最も微妙で混乱しますが、しかし、最初の原則から始めたら理解することは簡単です。

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
reflect.Value.Setfloatをアドレス指定が不可能な値を使用した

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.

問題は、値7.1がアドレスが指定可能ではないということではありません。 vは設定できません。 設定可能性は、reflection Valueの特性であり、すべてのreflection Valuesがそれを有するわけではない。

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

ValueのCanSetメソッドは、Valueの設定可能性を報告します。 私達の場合。

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

prints

settability of v: false

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

設定できない値に対してSetメソッドを呼び出すのはエラーです。 では、設定可能性とは何ですか?

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

設定可能性は、アドレス可能性のようなものですが、より厳しいものです。 reflection objectは作成に使用された実際のストレージを変更することができるプロパティです。 設定可能性は、reflection objectが元のアイテムを保持するかどうかによって決まります。 私たちが言うとき

var x float64 = 3.4
v := reflect.ValueOf(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

xのコピーを渡します reflect.ValueOf、したがって、reflect.ValueOfへの引数として作成されたinterfaceの値は、x自身ではなくxのコピーです。 したがって

v.SetFloat(7.1)

were allowed to succeed, it would not update x, even though v looks like it was created from x. 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から作成されたように見えるとしても、xは更新されないでしょう。 代わりに、それはreflection valueの内部に格納されたxのコピーを更新し、x自体は影響を受けません。 このような操作は、混乱を生むだけで役に立ちません。設定可能性はこの問題を回避するために使用されるプロパティです。

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

これが奇妙に思われるかもしれませんが、そうではありません。 実際には普通ではない服装ではおなじみの状況です。では、 xを関数に渡すことを考えてみましょう:

f(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):

私たちは、x自身の値ではなく、xの値のコピーを渡したので、fでxを変更できるとは思わないでしょう。fでxを直接変更したい場合は、関数xのアドレス(xのポインタ)を渡す必要があります。

f(&x)

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.

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

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

やってみましょう。 最初にxを通常どおりに初期化し、それを指すreflection 値の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

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:

reflection objectのpは設定できませんが、設定したいpではありません。実際には*pです。 pが何を指しているかを知るために、ポインタを介して間接的に行われるValueのElemメソッドを呼び出して、その結果をvと呼ばれるreflection Valueに保存する。

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

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

出力が示す通り、vは設定可能なreflection objectです。

settability of v: true

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

vはxを表すので、最終的にv.SetFloatを使ってxの値を変更することができます:

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

The output, as expected, is

出力は、期待どおりです。

7.1
7.1

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.

Reflectionは理解するのが難しいかもしれませんが、何が起こっているのかを隠すことができるreflectionのTypesとValuesにもかかわらず、言葉の意味を正確にしています。 reflectionには、表現するものを変更するために、何かのアドレスが必要です。

構造体

Structs

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.

前の例では、vはポインタそのものではなく、単にポインタから導出されたものです。 この状況が発生する一般的な方法は、reflectionを使用して構造のフィールドを変更する場合です。 構造体のアドレスがあれば、そのフィールドを変更することができます。

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.

構造体の値tを解析する簡単な例を次に示します。 構造体のアドレスを使ってリフレクションオブジェクトを作成します。後で変更する必要があるからです。 次に、typeOfTをその型に設定し、簡単なメソッド呼び出しを使用してフィールドを反復処理します(詳細はパッケージを参照)。 struct型からフィールドの名前を抽出しますが、フィールド自体は通常のreflect.Valueオブジェクトです。

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

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.

ここではsettabilityについてもう一度説明します。Tのフィールド名は、構造体のエクスポートされたフィールドのみが設定可能であるため、Tのフィールド名は大文字(エクスポートされます)です。

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

sには設定可能なreflection objectが含まれているため、構造のフィールドを変更できます。

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}

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.

&tではなくtからsを作成するようにプログラムを修正した場合、SetIntとSetStringの呼び出しは失敗し、tのフィールドは設定できません。

結論

Conclusion

Here again are the laws of 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は、interface値から反射オブジェクトに向かう。
  • Reflectionは、reflection objectからinterface値に向かいます。
  • reflection objectを変更するには、その値を設定可能にする必要があります。
  • これらの法律を理解すれば、Goでの反映はずっと使いやすくなりますが、微妙なままです。 どうしても必要な場合を除いて使用し、出来れば避けるべき強力なツールです。

感想

勉強のために翻訳しましたが、思ったより分量多くて辛かった。