空インターフェース型(empty interface)は、すべての型と互換性のある型です。
interface{} とだけ記述すると、すべての型と互換性のある型を指定したことになります。
package main
import "fmt"
type student struct {
name string
score int
}
func main() {
var obj interface{}
obj = 100
fmt.Println(obj)
println(&obj)
obj = "Hello"
fmt.Println(obj)
println(&obj)
obj = 3.14
fmt.Println(obj)
println(&obj)
obj = [3]string{"Kate", "Jane", "Mary"}
fmt.Println(obj)
println(&obj)
obj = [ ]string{"Jack", "Bob", "John"}
fmt.Println(obj)
println(&obj)
obj = map[string]int{"english":100, "science":80, "math":60}
fmt.Println(obj)
println(&obj)
obj = student{name:"Jane", score:88}
fmt.Println(obj)
println(&obj)
}
100
0xc000070ec0
Hello
0xc000070ec0
3.14
0xc000070ec0
[Kate Jane Mary]
0xc000070ec0
[Jack Bob John]
0xc000070ec0
map[english:100 math:60 science:80]
0xc000070ec0
{Jane 88}
0xc000070ec0
すべて値が正常に表示されています。アドレスはすべて同じなので、同じ変数に代入されいることがわかります。
関数の引数に空インターフェース型を指定すると、すべての型を受けとることができる関数になります。
package main
import "fmt"
type student struct {
name string
score int
}
func show(obj interface{}) {
fmt.Println(obj)
}
func main() {
show(100)
show("Hello")
show(3.14)
show([3]string{"Kate", "Jane", "Mary"})
show([ ]string{"Jack", "Bob", "John"})
show(map[string]int{"english":100, "science":80, "math":60})
show(student{name:"Jane", score:88})
}
100
Hello
3.14
[Kate Jane Mary]
[Jack Bob John]
map[english:100 math:60 science:80]
{Jane 88}
引数で受け取った空インターフェース型のもともとの型を知りたい場合には、型アサーションと型スィッチという 2 つの方法があります。
まずは、型アサーションを紹介します。 アサーション(assertion、表明 主張)
package main
import "fmt"
type student struct {
name string
score int
}
func show(obj interface{}) {
v1, ok := obj.(int)
if ok {
fmt.Println("int", v1)
}
v2, ok := obj.(string)
if ok {
fmt.Println("string", v2)
}
v3, ok := obj.(float64)
if ok {
fmt.Println("float64", v3)
}
v4, ok := obj.([3]string)
if ok {
fmt.Println("array", v4)
}
v5, ok := obj.([ ]string)
if ok {
fmt.Println("slice", v5)
}
v6, ok := obj.(map[string]int)
if ok {
fmt.Println("map", v6)
}
v7, ok := obj.(student)
if ok {
fmt.Println("student", v7)
}
}
func main() {
show(100)
show("Hello")
show(3.14)
show([3]string{"Kate", "Jane", "Mary"})
show([ ]string{"Jack", "Bob", "John"})
show(map[string]int{"english":100, "science":80, "math":60})
show(student{name:"Jane", score:88})
}
int 100
string Hello
float64 3.14
array [Kate Jane Mary]
slice [Jack Bob John]
map map[english:100 math:60 science:80]
student {Jane 88}
v1, ok := obj.(int)
obj の型が int だったら、v1 にはその値が代入され、ok には true が代入されます。もし obj の型が int でなかったら v1 には何も代入されず、ok には false が代入されます。
型アサーションが if 文を利用したものでしたが、型スィッチは switch 文を利用したものです。こちらの方がすっきりと記述できます。
package main
import "fmt"
type student struct {
name string
score int
}
func show(obj interface{}) {
switch v := obj.(type) {
case int:
fmt.Println("int", v)
case string:
fmt.Println("string", v)
case float64:
fmt.Println("float64", v)
case [3]string:
fmt.Println("array", v)
case [ ]string:
fmt.Println("slice", v)
case map[string]int:
fmt.Println("map", v)
case student:
fmt.Println("student", v)
}
}
func main() {
show(100)
show("Hello")
show(3.14)
show([3]string{"Kate", "Jane", "Mary"})
show([ ]string{"Jack", "Bob", "John"})
show(map[string]int{"english":100, "science":80, "math":60})
show(student{name:"Jane", score:88})
}
int 100
string Hello
float64 3.14
array [Kate Jane Mary]
slice [Jack Bob John]
map map[english:100 math:60 science:80]
student {Jane 88}
switch v := obj.(type) {
この 1 行で、v には obj の値が代入され、switch 文には、obj の型が自動的に渡されています。
case int:
実際に case 句で、型を判定できます。