goのstructとinterface辺りのメモ
・ポインタはよしなにdereferenceしてくれる
http://golang.org/ref/spec#Selectors
http://play.golang.org/p/WtCuLsr824
package main type T0 struct { x int } func (recv *T0) M0(){ println("*T0:",recv.x) } type T1 struct { y int } func (recv T1) M1(){ println("M1:",recv.y) } type T2 struct { z int T1 *T0 } func (recv *T2) M2(){ println("*T2:",recv.z) } func main(){ var p *T2 = &T2{3,T1{2},&T0{1}} println(p.z) println((*p).z) (*p).M2() p.M2() (*p).T1.M1() p.M1() (*(*p).T0).M0() p.M0() (*p).M0() (*T2).M2(p) (T1).M1(p.T1) (*T0).M0(p.T0) }
3 3 *T2: 3 *T2: 3 M1: 2 M1: 2 *T0: 1 *T0: 1 *T0: 1 *T2: 3 M1: 2 *T0: 1
ポインタをよしなに扱ってくれるので以下のように呼び出せる (ただし当然M0()内でのrecvの変更は呼び出し元に影響しない)
http://play.golang.org/p/DE_2nzUOsq
package main type T0 struct { x int } func (recv T0) M0(){ recv.x = 4; println("*T0:",recv.x) } func main(){ var t *T0 = &T0{2} t.M0() println(t.x) }
*T0: 4 2
・interface type にはinterfaceを実装するものが入れられる.interace type から呼び出せるのはinterfaceで宣言されたメソッドのみ.interface type から特定のtypeに変換したい場合はtype assertionを使う
・以下の例では &Bar{}をtype Fooの変数に代入しているが, *Bar をレシーバとしてFoo()が定義されており interface Fooを満足しているでok.このとき別に type Foo のポインタを使うわけではない.
http://golang.org/ref/spec#Type_assertions
http://play.golang.org/p/aItoeCpxqx
package main import "fmt" type Foo interface { Foo() string } type Bar struct{} type Boo struct{} func (b *Bar) Foo() string { return "Bar: Foo()" } func (b *Bar) Bar() string { return "Bar: Bar()" } func (b *Boo) Foo() string { return "Boo: Foo()" } func (b *Boo) Boo() string { return "Boo: Boo()" } func main() { var f Foo = &Bar{} fmt.Println(f.Foo()) if b, ok := f.(*Bar); ok { fmt.Println(b.Bar()) } if b, ok := f.(*Boo); ok { fmt.Println(b.Boo()) } }
Bar: Foo() Bar: Bar()
interface typeのポインタを使う例 (使い道ある?)
http://play.golang.org/p/-WK_XHE3lX
package main import "fmt" type Foo interface { Foo() string } type Bar struct{} type Boo struct{} func (b *Bar) Foo() string { return "Bar: Foo()" } func (b *Bar) Bar() string { return "Bar: Bar()" } func main() { var b *Bar = &Bar{} var pf *Foo = new(Foo) *pf = b fmt.Println((*pf).Foo()) }
・あるtypeの変数が特定のinterface typeを満足しているか調べるには,調べたい変数をinterface{}にキャストしてtype assertionを使う (type assertionできるのは interface typeのみ)
http://play.golang.org/p/brB8FOHjgc
package main import "fmt" type Foo interface { Foo() string } type Bar struct{} type Boo struct{} func (b *Bar) Foo() string { return "Bar: Foo()" } func (b *Bar) Bar() string { return "Bar: Bar()" } func main() { var b *Bar = &Bar{} if f, ok := interface{}(b).(Foo); ok { fmt.Println(f.Foo()) } }
Bar: Foo()
・type assertionするのにswitch文が使える
http://golang.org/ref/spec#Switch_statements
http://play.golang.org/p/owDgNUWLGC
package main import "fmt" type Foo interface { Foo() string } type Bar struct{} type Boo struct{} func (b *Bar) Foo() string { return "Bar: Foo()" } func (b *Bar) Bar() string { return "Bar: Bar()" } func (b *Boo) Foo() string { return "Boo: Foo()" } func (b *Boo) Boo() string { return "Boo: Boo()" } func main() { var f Foo = &Bar{} switch f.(type) { case (*Bar) : { fmt.Println(f.(*Bar).Bar()) } case (*Boo) : { fmt.Println(f.(*Boo).Boo()) } default :{ fmt.Println("unkown type") } } }
Bar: Bar()
まとめ: 普通に公式のspecが分かりやすい