前端时间说了不少golang常用库包的使用,貌似没有详细说struct interface的概念。在说interface之前,我们知道在Golang 中是没有类class 的概念,golang是通过 interface 类型接口实现的继承多态的效果。
一个 interface 类型定义了一个方法集做接口。 使用golang实现继承时,我们只要记得要给我们的interface类型实现一个method,就完成了对interface的使用。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。
我们首先要区分出goalng的方法和函数。他们之间虽然都是通过func定义的,但还是有区别的。
这是函数,很直接的函数。
1 2 3 4 |
func go() { fmt.Println('go to home') } |
这是struct结构体,后面的move()函数是car结构体的一个方法。 如果move的方法类型是g *car,那么g是指针。 初始化了car后,可以直接用car的对象调用move方法。
1 2 3 4 5 6 7 8 9 |
type car struct{ name string num int } func (g car) move(){ fmt.Println("driver car ,xiaorui.cc ") } |
另外在golang里某个函数想调用其他函数有这么几个用法。 方法,基于方法的interface接口,直接传参传对象。
然后来说下interface的用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//使用type定义一个interface type Xiaorui interface { Play() Start(msg string) } // 定义a为空接口 var a interface{} var i int = 5 s := "Hello world" // a可以存储任意类型的数值 a = i a = s |
一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。是不是很有用啊!
这是一个golang interface的实例代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
#xiaorui.cc package main import "fmt" type S struct { i int } func (p *S) Get() int { return p.i } func (p *S) Put(v int) { p.i = v } type I interface { Get() int Put(int) } func f1(p I) { fmt.Println(p.Get()) p.Put(888) } func f2(p interface{}) { switch t := p.(type) { case int: fmt.Println("this is int number") case I: fmt.Println("I:", t.Get()) default: fmt.Println("unknow type") } } //指针修改原数据 func dd(a *S) { a.Put(999) fmt.Println(a.Get(), "in dd func") } //临时数据 func aa(a S) { a.Put(2222) fmt.Println(a.Get(), "in aa func") } func main() { var s S s.Put(333) fmt.Println(s.Get()) f1(&s) fmt.Println(s.Get()) f2(&s) dd(&s) fmt.Println(s.Get()) aa(s) fmt.Println(s.Get()) } |
运行后的结果是:
1 2 3 4 5 6 7 8 9 |
333 333 888 I: 888 999 in dd func 999 2222 in aa func 999 |
下面是我的自问自答,也是我学习golang中的疑问… 请忽视问题的质量.
第一个问题,为什么s可以直接调用Put函数
首先s是用S结构体创建的,S有Get() Put()两个方法。所以s可以执行Put()
第二个问题,f函数为什么也能Get()
因为S实现了I类型的接口,换句话说,S实现了I interface类型定义好的方法,那么I定义也就有了Get方法。
第三个问题, f2的interface{}空接口用途
interface{}空接口可以是任何类型,我们可以在逻辑用断言的方式区别他是什么类型,然后根据类型做相应的处理。对应到上面的代码, 我给你给他传任何值,f2因为是空间口都会接收进来。
后面的 t := p.(type)是断言,所谓的断言就是区分他的type类型。 如果你不想使用switch,可以用下面的笨方法。
1 2 3 4 5 6 7 8 9 10 |
func g(something interface{}){ if t,ok := something.(I); ok{ fmt.Println("I:",t.Get()) }else if t,ok := something.(int); ok{ fmt.Println("int:",t) }else{ fmt.Println("not found:",something) } } |
空接口可代表任何类型,可做形参和返回类型
第四个问题,f1 f2 为什么要使用指针?
看代码中的类型,我被自己坑了好几次。
func (p *S) Get() int {
func (p *S) Put(v int) {
上面是interface的种种用法。下面是个google出来的一个goalng interface的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#xiaorui.cc package main import ( "fmt" ) //定义了一个接口 type I interface { Get() int Put(int) } type S struct{ i int } func (p *S) Get() int { return p.i } func (p *S) Put(v int) { p.i = v } type R struct{ i int } func (p *R) Get() int { return p.i } func (p *R) Put(v int) { p.i = v } func f1(p I) { fmt.Println(p.Get()) p.Put(1) } //interface{}空接口,能接受任何类型。.(I)是类型断言. func f2(p interface{}) { if t, ok := p.(S); ok { fmt.Println("S:", t) } else if t, ok := p.(I); ok { fmt.Println("I:", t.Get()) } } func f3(p interface{}) { switch t := p.(type) { case S: fmt.Println("S:", t.Get()) case R: fmt.Println("R:", t.Get()) case I: fmt.Println("I:", t.Get()) default: fmt.Println("unknow type") } } func main() { s := S{101} f1(&s) f2(&s) r := R{1111} f3(&r) } |
最后啰嗦一下. 上面的结构S实现了I接口的两个方法,因此可以说是S实现了I接口。又因为S实现了I,因此可以f函数向其传递s,而且可以调动s的那两个方法。
对于golang interface我没有从更深的层面去讲述,为什么? 因为我也不懂太深… 以上对于interface讲述有不对的地方,欢迎来指点下。
要看清方法是否是指针.
1 2 3 4 |
# command-line-arguments ./in.go:44: cannot use s (type S) as type I in argument to f1: S does not implement I (Get method has pointer receiver) |
有疑问加站长微信联系(非本文作者)