接口类型总是代表着某一种类型(即所有实现它的类型)的行为。
一个接口类型的声明通常会包含关键字type、类型名称、关键字interface以及由花括号包裹的若干方法声明。
type Animal interface {
Grow()
Move(string) string
}
接口类型中的方法声明是普通的方法声明的简化形式。
它们只包括方法名称、参数声明列表和结果声明列表。
其中的参数的名称和结果的名称都可以被省略。
不过,出于文档化的目的,建议写上它们。
因此,Move方法的声明至少应该是这样的:
Move(new string) (old string)
一个数据类型所拥有的方法集合中包含了某一个接口类型中的所有方法声明的实现,那么就可以说这个数据类型实现了那个接口类型。
不能在一个非接口类型的值上应用类型断言来判定它是否属于某一个接口类型的。
我们必须先把前者转换成空接口类型的值。
Go语言的类型转换规则定义了是否能够把一个类型的值转换另一个类型的值。
空接口类型即是不包含任何方法声明的接口类型,用interface{}表示,常简称为空接口。
正因为空接口的定义,Go语言中的包含预定义的任何数据类型都可以被看做是空接口的实现。
我们可以直接使用类型转换表达式把一个*Person类型转换成空接口类型的值.
p := Person{"Robert", "Male", 33, "Beijing"}
v := interface{}(&p)
然后就可以在v上应用类型断言了,即:
h, ok := v.(Animal)
类型断言表达式v.(Animal)的求值结果可以有两个。
第一个结果是被转换后的那个目标类型(这里是Animal)的值,
而第二个结果则是转换操作成功与否的标志。
显然,ok代表了一个bool类型的值。
它也是这里判定实现关系的重要依据。
package main
import (
"fmt"
)
type humaner interface {
sayHello() //接口只有声明没有实现。
}
type Studnt struct {
name string
age int
}
func (tmp *Studnt) sayHello() {
fmt.Println("i am student")
}
type Teacher struct {
name string
age int
}
func (tmp *Teacher) sayHello() {
fmt.Println("i am Teacher")
}
func whoSayHi(i humaner) {
i.sayHello()
}
func main() {
//定义接口类型变量
var h humaner
//实现了此接口的方法类型,那么这个类型的变量就可以给i赋值。
s := &Studnt{"break", 20}
h = s
h.sayHello()
t := &Teacher{"Tony", 20}
//通过接口调用实现多态
whoSayHi(s)
whoSayHi(t)
//创建一个切片
x := make([]humaner, 2)
x[0] = s
x[1] = t
for _, hum := range x {
hum.sayHello()
}
}
package main
import (
"fmt"
)
type humaner interface { //子集
sayHello() //接口只有声明没有实现。
}
type persion interface { //超集
humaner //匿名字段继承sayHello
sing(lrc string)
}
type Studnt struct {
name string
age int
}
//实现了sayHello
func (tmp *Studnt) sayHello() {
fmt.Println("i am student")
}
//实现了sing
func (tmp *Studnt) sing(lrc string) {
fmt.Println(lrc)
}
func main() {
//定义一个接口类型变量
var per persion
s := &Studnt{"break", 20}
per = s
per.sayHello() //继承过来的接口
per.sing("la la la")
//超集可以转化为子集,反过来不行
var h humaner
h = per
h.sayHello()
//空接口 实际上就是一个万能类型, 可以保存任意类型值
var i interface{} = 1
fmt.Println(i)
i = "abc"
fmt.Println(i)
//类型断言
if value, ok := i.(string); ok == true {
fmt.Println(value)
}
i = Studnt{"break", 20}
if value, ok := i.(Studnt); ok == true {
fmt.Println(value.name)
}
switch i.(type) {
case Studnt:
fmt.Println("Studnt")
case int:
fmt.Println("int")
}
}
反射例子
type Student struct {
Name string
Age int
Score float32
}
func test(b interface{}) {
t := reflect.TypeOf(b)
fmt.Println(t)
v := reflect.ValueOf(b)
k := v.Kind()
fmt.Println(k)
iv := v.Interface()
stu, ok := iv.(Student)
if ok {
fmt.Printf("%v %T
", stu, stu)
}
}
func TestStruct(a interface{}) {
tye := reflect.TypeOf(a)
val := reflect.ValueOf(a)
kd := val.Kind()
if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
fmt.Println("expect struct")
return
}
num := val.Elem().NumField()
val.Elem().Field(0).SetString("stu1000")
for i := 0; i < num; i++ {
fmt.Printf("**%d %v
", i, val.Elem().Field(i).Kind())
}
fmt.Printf("struct has %d fields
", num)
tag := tye.Elem().Field(0).Tag.Get("json")
fmt.Printf("tag=%s
", tag)
numOfMethod := val.Elem().NumMethod()
fmt.Printf("struct has %d methods
", numOfMethod)
var params []reflect.Value
val.Elem().Method(0).Call(params)
}
test(a)
TestStruct(a)