[golang] interface

177 阅读4分钟

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)