Interface の謎
今回も軽めの小ネタで。
まず,文字列の配列を表示するだけの単純なコードを書いてみる。
package main
import "fmt"
func main() {
strlist := []string{"alpha", "beta", "gamma"}
fmt.Println(strlist)
}
結果は
[alpha beta gamma]
となる。
配列1 の中身をそのままダンプ出力しているだけなので,まぁ当たり前っちゃあ当たり前。
では,配列のダンプではなくきちんと項目を列挙したいとしよう。
やり方は色々あるが簡単に “...
” トークンを使って
package main
import "fmt"
func main() {
strlist := []string{"alpha", "beta", "gamma"}
fmt.Println(strlist...)
}
と配列を展開すればいんじゃね? って思うよね,普通。
fmt
.Println()
関数の定義を見ても
func Println(a ...interface{}) (n int, err error)
となっているし,問題ないように見える。
でもこれはうまくいかない。 これを実行しようとすると
prog.go:7: cannot use strlist (type []string) as type []interface {} in argument to fmt.Println
とエラーになる。
実は []string
型の strlist
は fmt
.Println()
関数に渡す際に []interface{}
型ではなく interface{}
型に必ずキャストされる。
だから strlist...
と展開しようとしても「そりゃあ無理(←超意訳)」と怒られてしまうわけだ。
Go 言語の型(type)は
type Msg []string
のように配列やポインタも型として定義できてしまうことを思い出して欲しい。
じゃあ,明示的なキャストならいけるのかと思ったが
package main
import "fmt"
type Msg []string
func main() {
strlist := []string{"alpha", "beta", "gamma"}
fmt.Println(([]interface{})(strlist)...)
}
結果は
prog.go:9: cannot convert strlist (type []string) to type []interface {}
と,これもエラーになった。
ではどうすればいいのかというと []interface{}
型の配列を用意してそこに値をコピーする。
先程のコードであれば
package main
import "fmt"
type Msg []string
func main() {
strlist := []string{"alpha", "beta", "gamma"}
var list = make([]interface{}, 0)
for _, str := range strlist {
list = append(list, str)
}
fmt.Println(list...)
}
とすれば
alpha beta gamma
のようにめでたく列挙される。
この問題は fmt
.Println()
関数だけじゃなく,ある型の配列を []interface{}
型にキャストしようとする際は必ず発生するようだ2。
いや,「“cannot use strlist (type []string) as type []interface {} in argument to fmt.Println
” なんてコンパイルエラーを出せるならコンパイラ側でなんとかしてよ」と思うのだが,どうも無理らしい。
やれやれ。