【Go学习笔记】7 -- 类型系统 -- Interface

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())

反射的话,反射的字段必须是可以修改的(可读写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值