interface 类型定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。
interface可以被任意的对象实现;- 一个对象可以实现任意多个
interface; - 任意类型都实现了
interface{},也就是包含 0 个 method 的interface; - 必须由其他非
interface类型实现,而不能自我实现;
interface 变量
interface 变量可以存实现这个 interface 的任意类型的对象。
type Men interface {
SayHi()
Sing(lyrics string)
}
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type 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)
}
func main() {
jack := Human{"Jack", 25, "222-111-XXX"}
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
tom := Employee{Human{"Tom", 37, "222-444-XXX"}, "Things Ltd.", 5000}
x := make([]Men, 3)
x[0], x[1], x[2] = jack, tom, mike
for _, value := range x {
value.SayHi()
}
}
Hi, I am Jack you can call me on 222-111-XXX
Hi, I am Tom, I work at Things Ltd.. Call me on 222-444-XXX
Hi, I am Mike you can call me on 222-222-XXX
interface{}
interface{} 对于描述起不到任何的作用(因为它不包含任何的 method),但是 interface{} 可以存储任意类型的数值,它有点类似于 C 语言的 void* 类型。
一个函数把 interface{} 作为参数,那么可以接受任意类型的值作为参数,如果一个函数返回 interface{},那么也就可以返回任意类型的值。
var a interface{}
var i int = 5
s := "Hello world"
a = i
fmt.Println("a", a)
a = s
fmt.Println("a", a)
a 5
a Hello world
interface 函数参数
fmt.Println 是常用的一个函数,可以接受任意类型的数据。
type Stringer interface {
String() string
}
任何实现了 String() 的类型都能作为参数被 fmt.Println 调用。
type Human struct {
name string
age int
phone string
}
func (h Human) String() string {
return "❰" + h.name + " - " + strconv.Itoa(h.age) + " years - ✆ " + h.phone + "❱"
}
func main() {
Bob := Human{"Bob", 39, "000-7777-XXX"}
fmt.Println("This Human is : ", Bob)
}
This Human is : ❰Bob - 39 years - ✆ 000-7777-XXX❱
interface 变量存储的类型
if...else
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
} else {
fmt.Printf("list[%d] is of a different type\n", index)
}
}
}
list[0] is an int and its value is 1
list[1] is a string and its value is Hello
list[2] is a Person and its value is (name: Dennis - age: 70 years)
switch
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 //an int
list[1] = "Hello" //a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Printf("list[%d] is of a different type", index)
}
}
}
list[0] is an int and its value is 1
list[1] is a string and its value is Hello
list[2] is a Person and its value is (name: Dennis - age: 70 years)
element.(type) 只能结合 switch 一起使用。
interface 嵌入
type Element interface {
f1() int
f2() float32
}
type Element02 interface {
Element
f3()
}
type A struct{}
func (a A) f1() int {
return 1
}
func (a A) f2() float32 {
return 1
}
type B struct{}
func (b B) f1() int {
return 1
}
func (b B) f2() float32 {
return 1
}
func (b B) f3() {}
func main() {
var element []Element
element = append(element, new(A))
var element02 []Element02
element02 = append(element02, new(B))
}
反射
Go 语言实现了反射,所谓反射就是能检查程序在运行时的状态。
使用 reflect 一般分成三步:首先需要把它转化成 reflect 对象(reflect.Type 或者 reflect.Value,根据不同的情况调用不同的函数)。
t := reflect.TypeOf(i) // 得到类型的元数据,通过 t 能获取类型定义里面的所有元素
v := reflect.ValueOf(i) // 得到实际的值,通过 v 能获取存储在里面的值,还可以去改变值
转化为 reflect 对象之后,就可以进行一些操作了,也就是将 reflect 对象转化成相应的值。
tag := t.Elem().Field(0).Tag // 获取定义在第一个字段里面的标签
name := v.Elem().Field(0).String() // 获取存储在第一个字段里面的值
获取反射值能返回相应的类型和数值。
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())
type: float64
kind is float64: true
value: 3.4
如果需要通过反射修改值,那么反射的字段必须是可读写的。
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
panic: reflect: reflect.Value.SetFloat using unaddressable value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x8f8fc5)
C:/Program Files/Go/src/reflect/value.go:262 +0x85
reflect.flag.mustBeAssignable(...)
C:/Program Files/Go/src/reflect/value.go:249
reflect.Value.SetFloat({0x958120, 0xc000012030, 0x0}, 0x401c666666666666)
C:/Program Files/Go/src/reflect/value.go:1964 +0x49
main.main()
D:/Developer/Go/src/go-magic/test/main.go:15 +0xb3
exit status 2
var x float64 = 3.4
p := reflect.ValueOf(&x)
v := p.Elem()
v.SetFloat(7.1)