logo

アルパカログ

Go言語 interface型のスライスにstruct型のスライスを代入できない

変数やメソッドの仮引数としてインターフェース型のスライスを定義しておき、実際には構造体のスライスを渡したいというケースがあります。

これはスライスでなければ上手く動きます。しかし、スライスではエラーになってしまいます。

次のようなコードです。

package main

import "fmt"

type Human interface {
	Greet()
}

type PoliceOfficer struct{}

func (po *PoliceOfficer) Greet() {
	fmt.Println("Hi")
}

func main() {
	var human Human

	policeOfficer := &PoliceOfficer{}

	human = policeOfficer
	human.Greet() // -> "Hi"

	var humans []Human

	policeOfficers := []*PoliceOfficer{policeOfficer}

	humans = policeOfficers // -> cannot use policeOfficers (variable of type []*PoliceOfficer) as type []Human in assignment
}
インターフェース型のスライスに構造体のスライスを代入することはできない

main() 関数を見てください。

最初に Human インターフェース変数 humanPoliceOfficer 型のポインタ policeOfficer を代入しています。

これは問題なく動作します。

次に Human インターフェース型のスライス humansPoliceOfficer 型のポインタのスライス policeOfficers を代入しようとしていますが、これはエラーになってしまいます。

理由は Go Interface Slice (Japanese) に記載されています。

[]interface{} の変数はインターフェースではありません!これは要素型がたまたま interface{} のスライスなのです。

スライスの要素のデータ長がインターフェースと構造体で異なることにより代入できないといわけです。

解決方法

ではどうすれば良いかと言うと、少し面倒ですが for ループを使って1個ずつ要素を代入します。

コード例は下記です。

var humans []Human

policeOfficers := []*PoliceOfficer{policeOfficer}

for _, po := range policeOfficers {
	humans = append(humans, po)
}

以上です。

この記事では、Go の interface 型のスライスに struct 型のスライスを代入できない理由と解決方法を説明しました。