Interface 是一组method的组合,我们通过method来定义对象的一组行为。
Interface 类型
定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。如下:
type Human struct{
name string
age int
phone string
}
type Student string{
Human //匿名字段
school string
loan float32
}
type Employee string{
Human
company string
money float32
}
// Human 实现 Sayhi 方法
func (h *Human) Sayhi(){
fmt.Printf("Hi, I'm %s you can call me %s\n", h.name, h.phone)
}
// Human 实现 sing 方法
func (h *Human) sing(lyrics string){
fmt.Printf("la la, la..", lyrics)
}
// Human 对象实现 Guzzle 方法
func (h *Human) Guzzle(beerStein string){
fmt.Printf("Guzzle Guzzle ..", beerStein)
}
// Employee 重载 Human的Sayhi方法
func (e *Employee) Sayhi(){
fmt.Printf("Hi, I'm %s, I work at %s, Call me on %s\n", e.name, e.company, e.phone)
}
// Student 实现 BorrwMoney 方法
func (s *Student)BorrwMoney(amount float32){
s.loan += amount // again and again and ……
}
// 定义 interface
type Men interface{
Sayhi()
sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChap interface{
Sayhi()
sing(song string)
BorrwMoney(amount float32)
}
通过上面的内容,interface可以被任意的对象实现。同时,一个对象可以实现任意多个interface。
任意的类型都实现了空interface(定义: interface{})。
interface 值
如果我们定义了个interface 的变量,那么这个变量里可以实现这个interface的任意类型的对象。
如上面的例子中,定义了 Man interface类型的变量m,则m里可以存 Human Student或是Employee的值。
interface 就是一组抽象的方法集合。它必须由其他非interface类型实现。不能自我实现。如下代码
package main
import "fmt"
type Human struct{
name string
age int
phone string
}
type Student struct{
Human
school string
loan float32
}
tpye Employee struct{
Human
company string
money float32
}
func (h *Human) Sayhi(){
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h *Human) sing(lyrics string){
fmt.Println("La la la la...", lyrics)
}
func (e *Employee) Sayhi(){
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name, e.company, e.phone)
}
// interface Men 被 Human Student Employee实现
type Men interface{
Sayhi()
sing(lyrics string)
}
func main(){
mike := Student{Human{"Mike",25,"123456789"}, "MIT", 0.00}
tom := Student{Human{"tom",30,"4567891234"}, "Harvard", 100}
paul := Employee{Human{"paul",34,"987654321"}, "IBM", 1000}
// 定义Men类型的变量i
var i Men
// i 能存储Student
i = Mike
fmt.Println("This is Mike, a Student")
i.Sayhi()
i.sing("November rain")
// i 能存储Employee
i = paul
fmt.Println("This is paul, an Employee")
i.Sayhi()
i.sing("Born to be wild")
// 定义了slice Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men,3)
// 三个都是不同类型的元素,但是他们实现了interface同一个接口
x[0], x[1], x[2] = paul, mike, tom
for _, value := range x{
value.Sayhi()
}
}
空 interface
interface{} 不包含任何的method 。 空interface对描述不起任何作用,但是空interface在我们需要存储任意类型的数值时有用。
它可以存储任意类型的数值。
// 定义 a 为空接口
var a interface{}
var i int = 5
s := "Hello World"
// a 可以存储任意类型数值
a = i
a = 5
interface 函数参数
interface的变量可以持有任意实现interface类型的对象。我们是不是可以通过定义interface参数,让函数接收各种类型的参数
如: fmt.Println是常用的函数,其源码中有
type Stringer interface{
String() string
}
// 任何实现了String方法的类型都可以作为参数被 fmt.Println调用。
// 如下面的例子。
package main
import (
"fmt"
"strconv"
)
type Human struct{
name string
age int
phone string
}
// 通过这个方法 Human 实现了 fmt.Stringer
func (h *Human) String() string{
return "<"+h.name+" - "+strconv.Itoa(h.age)+" year - ✆ " +h.phone+">"
}
func main{
Bob := Human{"Bob", 27, "123456789"}
fmt.Println("This Human is: ", Bob)
}
interface 变量存储的类型
interface的变量里可以存储各种类型的数值,那么如何确定其存储的是哪种类型的对象呢。
通常有2中方法
Comma-ok 断言
Go 语言中有个语法,可以直接判断是否是该类型的变量。 value, ok = element(T)
这里的 value 就是变了的值。 ok 是一个bool 类型。 element 就是interface变量, T 是断言的类型
如果 element 里确实存储了 T 类型的数值,那么ok 返回的是 true ,否则返回false
switch 测试
element.(type) 语法不能再switch 外的任何逻辑里使用。
如果要在switch 外面判断一个类型就要使用 comma-ok
嵌入 interface
如果一个interface1 作为 interface2的一个嵌入字段,那么interface2 就包含了interface1里面的方法
// 源码包: container/heap 里面的定义
type Interface interface{
// 嵌入字段 sort.Interface
sort.Interface
// Push 方法
Push(x inter {})
// Pop element
Pop() interface{}
}
// sort.Interface 就是嵌入知道,就把sort.Interface的所有方法给隐式的包含进来了。
type Interface interface{
// Len is the number of elements in the collection.
len() int
// Less returns whether the element with index i should sort
// before the element with index j.
less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
反射
反射就是能检查程序在运行时的状态。我们一般使用reflect。
使用reflect一般分三步。要去反射一个类型的值,首先需要将其转化为reflect对象。如:
// 得到的类元数据,通过t 我们能获取类型定义里的所有元素
t := reflect.TypeOf(i)
// 得到实际值,通过v 我们获取存在里面的值。还可以改变值。
v := reflect.ValueOf(i)
转话为reflect对象后,我们就可以将reflect对象转化成相应的值,如:
// 获取定义在struct里的标签
tag := t.Elem().Field(0).Tag
// 获取存储在第一个字段里的值
name := v.Elem().Field(0).String()
获取反射值能返回相应的类型和数值
var x float64 = 3.3
v := reflect.ValueOf(x)
fmt.Println("type", v.Type())
fmt.Println("kind of float64". v.Kind() == reflect.Float64)
fmt.Println("value: ",v.Float())
反射的话,反射的字段必须是可以修改的(可读写)