Go 1.15 の reflect パッケージの変更の影響詳細について
Go 1.15 リリースノート 日本語訳 として、reflect パッケージの変更内容を日本語訳したものの、いまいち何を言っているのか分からなかったので確認してみた.
package main
import "reflect"
type u struct{}
func (u) M() {}
type t struct {
u
u2 u
}
func main() {
reflect.ValueOf(t{}).Method(0).Call(nil) // no problem
reflect.ValueOf(t{}).Field(0).Method(0).Call(nil) // panic on go1.15
reflect.ValueOf(t{}).Field(1).Method(0).Call(nil) // panic on go1.14 and go1.15
}
要するに go1.14 ではエクスポートされていないフィールドへアクセスすると panic: reflect: reflect.flag.mustBeExported using value obtained using unexported field
でパニックするのだが、唯一埋め込みフィールドだけが例外になっていた. これについても一貫性のため同様にパニックするようにしたようだ.
これが「パッケージ reflect
は、以前はエクスポートされていない埋め込みフィールドへのアクセスを許可していましたが、エクスポートされていないすべてのフィールドのメソッドへのアクセスを禁止するようになりました.」(原文: Package reflect
now disallows accessing methods of all non-exported fields, whereas previously it allowed accessing those of non-exported, embedded fields.) の意味するところだ.
で、そのアクセスを使ってしまっている場合の対応だが、埋め込みフィールドに対してメソッドを呼ばずに、埋め込みの外側の値に対してメソッドを呼べばいい. それが出来るがゆえに、継承みたいなことをしたければ埋め込みフィールドを使えと言われているわけだから.
これが「以前の動作に依存しているコードは、代わりに取り囲む変数に対応する昇格メソッドにアクセスするように更新する必要があります.」(原文: Code that relies on the previous behavior should be updated to instead access the corresponding promoted method of the enclosing variable.) の意味するところだ.
promoted method という言葉を知らなかったので意味が取れてなかったのだが、この言葉は仕様書に出ていた. The Go Programming Language Specification - Struct types にある. これを知っていれば一発で意味が取れたなあ.
まあ、この変更で困る人はほとんどいなそうですね.