GO言語のinterfaceとstructでハマったのでまとめてみる
今までPHPメインだったけどGO言語の勉強を始めてinterfaceとstructで
これで動くだろって適当に書いたらエラーで止まることが何度かあったのでまとめてみる
GO言語初心者なので当たり前のことを書いてると思うけど温かい目で見守ってほしい
こうしたほうがいいよというアドバイスなどあればコメントもらえると嬉しいです
実装環境など
- go version go1.20.3
structでinterfaceの使用
エラーで動かいけどこんなコードを書いてみる
type hoge interface {
SetNum(num int)
GetNum() int
}
type fuga struct {
num int
}
func (f *fuga) SetNum(num int) {
f.num = num
}
func (f fuga) GetNum() int {
return f.num
}
func Add(h hoge, num int) hoge {
num += h.GetNum()
h.SetNum(num)
return h
}
func main() {
f := fuga{10}
h := Add(f, 30)
fmt.Println(h.GetNum())
}
hogeというinterfaceを作りfugaというstructで使えるようにして
Addの引数をhogeにして加算するだけのもの
実行しようとするとこのようなエラーが
どうやらfugaのSetNumメソッドがポインタレシーバーなのがダメらしい
でもmainのAddで渡すのをポインタにすると実行できる
func main() {
f := fuga{10}
Add(&f, 30)
fmt.Println(f.GetNum())
}
$ go run main.go
40
SetNumのポインタレシーバーをやめれば実行はできるけどfugaの値を変更できないので想定と違う動きになってしまう
メソッドなどでインターフェスにしない場合は普通に実行できる
30 func main() {
f := fuga{10}
num := f.GetNum() + 30
f.SetNum(num)
fmt.Println(f.GetNum())
}
$ go run main.go
40
まとめ
interfaceのメソッドでポインタレシーバーを使用する場合はポインタ変数を使用する
interface型のメンバー変数
structにinreface型を定義して用途別でそこにstructを設定してみてまたもやエラーに
type hoge struct {
data interface{}
}
type fuga struct {
num int
}
func newHoge(fn func() interface{}) hoge {
return hoge{fn()}
}
func main() {
fn := func() interface{} {
return fuga{10}
}
h := newHoge(fn)
fmt.Println(h.data.num)
}
hogeのdataはinterface型なのでnumは無いとのこと
それはそうだよねPHPのmixed的なものかと思ったら全然違うものだった
型アサーションで型変換してあげればいいだけの話だけどPHPになれすぎてあのような書き方をしてしまった
func main() {
fn := func() interface{} {
return fuga{10}
}
h := newHoge(fn)
f := h.data.(fuga)
fmt.Println(f.num)
}
$ go run ./main.go
10
まとめ
当たり前だけどinterface型は勝手に別の型になったりしない
使用するときは型アサーションで変換するなどする
その他
これはなれの問題だけど最初のコードでAddにfugaのポインタを渡す場合
Addの引数のinterfaceであるhogeをポインタ指定してしまう
こんな感じのエラーになるものをついつい書いてしまう
func Add(h *hoge, num int) hoge {
num += h.GetNum()
h.SetNum(num)
return h
}
func main() {
f := fuga{10}
h := Add(&f, 30)
fmt.Println(h.GetNum())
}
一部翻訳すると「h.GetNum undefined (型 hoge はインタフェースへのポインタであり,インタフェースではない)」とのこと
インタフェースへのポインタはポインタ*なのでインタフェースではないとすごく当たり前のことが書かれてる
なるほどね
Discussion