【Go】[]string型は[]interface{}型ではない！

# はじめに
こんにちは、kenです。
最近、Goの空インターフェースについて勘違いをしていたことに気づいたので記事にします。
要点は表題の通り、「**[]string型は[]interface{}型ではない！**」ということです。
# 空インターフェースとは
そもそも空インターフェースとは何なのかについておさらいしておきます。すでに知ってるよという方は飛ばして貰ってOKです。
まずインターフェースというのはなにかというと「メソッドの集まりにより定義される、構造体の抽象度をより高くした型」のことです。
下のサンプルコードを見てください。ここでは`Human`インターフェースが`SelfIntroduction()`というメソッドにより定義されており、`Man`型・`Woman`型・`Robot`型はそれぞれ`SelfIntroduction()`というメソッドを持っているので、暗黙的にこの3つの型は`Human`インターフェースを実装しています。[^1]
[^1]: 「RobotはHumanじゃなくね？」という指摘はもっともなんですが今回は気にしないでください……

これにより`Human`インターフェースの型を引数にもつ`Hello()`関数は、渡される型が何であるかを気にすることなく統一的に扱うことができるため、簡潔に処理を書くことができています。

```go
package main

import "fmt"

type Man struct {
	Name string
}
type Woman struct {
	Name string
}

type Robot struct {
	Name string
}
type Human interface {
	SelfIntroduction() string
}

func (m Man) SelfIntroduction() string {
	return fmt.Sprintf("僕の名前は%sです。", m.Name)
}
func (w Woman) SelfIntroduction() string {
	return fmt.Sprintf("私の名前は%sです。", w.Name)
}
func (dora Robot) SelfIntroduction() string {
	return fmt.Sprintf("ぼく%sです。", dora.Name)
}
func Hello(h Human) string {
	return fmt.Sprint("こんにちは、", h.SelfIntroduction())
}
func main() {
	Nobita := Man{
		Name: "野比のび太",
	}
	Shizuka := Woman{
		Name: "源静香",
	}
	Dora := Robot{
		Name: "ドラえもん",
	}
	fmt.Println(Hello(Nobita))
	fmt.Println(Hello(Shizuka))
	fmt.Println(Hello(Dora))
}
```
```:output
こんにちは、僕の名前は野比のび太です。
こんにちは、私の名前は源静香です。
こんにちは、ぼくドラえもんです。
```
このサンプルコードは以下のリンクから実行することができます。

https://go.dev/play/p/7D95M8N8QQX

そして**空インターフェースというのは任意の型に互換性のあるインターフェースのこと** です。
インターフェースというのはメソッドの集まりによって定義されるものでしたが、空インターフェースはその定義に使われるメソッドが一つもない、つまりなにもメソッドを実装していなくても空インターフェースの要件は満たされるため任意の型は空インターフェースを実装しているといえる、ということです。
よって、次のように空インターフェースで宣言された変数にはどんな型を代入してもエラーは起きません。

```go
var obj interface{}

obj = 1                 // int
obj = "hoge"            // string
obj = false             // bool
obj = []string{1, 2, 3} // []string
```
# 本題へ
ではここからは過去の私がしていた勘違いについて見ていきます。
先ほど私は
> **空インターフェースというのは任意の型に互換性のあるインターフェースのこと** 

といいましたね。そして
> 任意の型は空インターフェースを実装している

> 空インターフェースで宣言された変数にはどんな型を代入してもエラーは起きません

ともいいました。よって`string`型はもちろん空インターフェース`interface{}`型でもあります。

それなら`[]string`型は`[]interface{}`型とみなせますよね。なぜなら`[]string`型は`interface{}`型でもある`string`型を並べたスライスなのだから……

**はい、これ間違いです。。。**
**実際には`[]string`型は`[]interface{}`型ではありません**
私がこの勘違いをしたのは次のようなコードを書いているときです。
`[]interface{}`型を引数にとる関数に`[]string`型を渡したところエラーが起きてしまいました。
```golang
package main

func hoge(objs []interface{}) {
	// なんらかの処理
}
func main() {
	var str []string = []string{"foo", "bar"}
	hoge(str) // ここでエラー
}
```
```:エラーメッセージ
cannot use str (variable of type []string) as []interface{} value in argument to hoge
```
最初このエラーメッセージを読んだときは
「えっ、`[]string`型が`[]interface{}`型ではないって、そんなわけなくない？？」
と思いました。（そんなわけありました）
不思議に思っていたところ先輩から次のサイトを教えていただきました。

https://golang.shop/post/go-interface-slice-ja/

そのなかの次の記述が言い得て妙だと思ったので引用します。

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

た、たしかに。。。

ではどうすればよかったのかというと、これもリンク先のサイトに答えがあります。ただスライスの個々の要素を空インターフェース型へと変換するだけです。
```go
package main

func hoge(objs []interface{}) {
	// なんらかの処理
}
func main() {
	var str []string = []string{"foo", "bar"}
	var objs []interface{}
	for i, s := range str {
		objs[i] = s //ここで個々の要素をinterface{}型へ
	}
	hoge(objs) // エラーが起きない！
}
```
# まとめ
Goは静的型付け言語です。型がぴったり同じでなかったら、エラーで教えてくれます。
そして`[]interface{}`は要素が`interface{}`のスライスで、これはインターフェースでなくれっきとした型です。それならば`[]string`とは型が違うと、エラーで教えてくれるのも納得ですね。勉強になりました。

# おまけ
空インターフェースの配列に限らず、あるインターフェースを実装している型のスライスをそのインターフェースのスライスとして扱いたい場合は、明示的に型変換してからでないとエラーが起きます。
（なんとなく、これは「まあそうなるだろうな」という気持ちになりました。空インターフェースの場合だけ勘違いをしてしまうのは、空インターフェースの**任意の型と互換性をもつ**という強烈なインパクトが原因なんでしょうかね。。。）
```golang
package main

import "fmt"

type Man struct {
	Name string
}

type Human interface {
	SelfIntroduction() string
}

func (m Man) SelfIntroduction() string {
	return fmt.Sprintf("僕の名前は%sです。", m.Name)
}
func Hello(h Human) string {
	return fmt.Sprint("こんにちは、", h.SelfIntroduction())
}
func PrintHello(hs []Human) {
	for _, h := range hs {
		fmt.Println(Hello(h))
	}
}
func main() {
	Nobita := Man{
		Name: "野比のび太",
	}
	Gian := Man{
		Name: "剛田武",
	}
	Suneo := Man{
		Name: "骨川スネ夫",
	}
	var Men []Man = []Man{
		Nobita, Gian, Suneo,
	}
	PrintHello(Men) // ここでエラーが出る
}

```
```:エラーメッセージ
cannot use Men (variable of type []Man) as []Human value in argument to PrintHello
```

ここまで読んでいただき、ありがとうございました。間違いなどあればコメントにてご指摘いただけますと幸いです。