加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

golang 接口

发布时间:2020-12-16 19:11:28 所属栏目:大数据 来源:网络整理
导读:1、自定义类型存入接口的内存布局 接口值是一个两个字节长度数据结构,第一个字节包含一个指向内部表的指针(iTable),包含了存储的值的类型信息及和这个值判刑的一组方法。第二个字节指向所存储值的指针。 如果将指针赋值给接口,则类信息会存储一个指向保
1、自定义类型存入接口的内存布局
接口值是一个两个字节长度数据结构,第一个字节包含一个指向内部表的指针(iTable),包含了存储的值的类型信息及和这个值判刑的一组方法。第二个字节指向所存储值的指针。

如果将指针赋值给接口,则类信息会存储一个指向保存的类型的指针,接口的第二个字节依旧保存指向实体值的指针。(图B)


图A


图B


2、方法接收者(方法集)
自定义类型 T 的值的指针(t *T)的方法集,由接收者为 T 和 *T 的组成,如果在指针上调用一个接受值类型的方法,go会自动将该指针解引用,并将指针所指的底层值作为方法的接收者


自定义类型 T 的值(t T)的方法集,由接收者为 T的组成。如果我们只有一个值 T,仍然可以调用一个接收者为指针类型的方法,这可以借助于go语言传值的地址的能力实现,前提是该值是可寻址的(即它是一个变量,一个解引用指针,一个数组或切片项,或者结构体中的一个可寻址字段)。因此,假设我们这样调用t.Method(),其中Method() 需要一个指针接收者,而t是一个可寻址的值,go语言会把这个调用等同于(&t).Method()。

为什么会有这种限制?

因为编译器并不是总能自动获得一个值的地址。例如:自定义类型,type Integer int,就获取不到Integer 类型值的地址



所以不管是T 或者 *T 的方法集,在调用上是没有区别的。
接收者:
如果是T 则参数为传入参数的一个copy,在方法内的操作不会影响函数外面的值。(如果属性有引用类型,也会有影响。copy 的只是引用类型下的类型类型的指针)
如果是*T 则在函数内修改参数,影响到函数外的值(指针的用途)。

示例代码:

package main
import "fmt"

//user 结构
type user struct {
	name  string
	email string
}
//sendMail 方法绑定在user 上
func (u user) sendMail() {
	fmt.Printf("send mail to %s,%s n",u.name,u.email)
}
//printName 方法绑定在user 指针上
func (u *user) printName() {
	fmt.Printf("user name %s n",u.name)
}

func main() {
	u := user{"zhangsan","xxx@gmail.com"}
	u.sendMail()
	u.printName()

	u2 := &user{"zhangsan2","xxx2@gmail.com"}
	u2.sendMail()
	u2.printName()

}
3、接口实现
方法集:方法集定义了一组关联到给定类型的值或者指针的方法。定义方法时使用的接收者的类型决定了这个方法的关联到的值,还是关联到指针,还是两个都关联。
GO 语言规范定义的方法集规则:T 类型的方法集只包含值接收者声明的方法, *T 类型的方法集包含值接收声明的方法,也包含指针接收者声明的方法。也就是说:如果 *T 接收者来实现的一个接口,只有指向 T 类型的指针才能够实现接口。T 接收者来实现接口,那么T 和 *T 类型都能够实现了这个接口。

示例代码:

package main

import "fmt"

/**
user 类型
*/
type user struct {
	name  string
	email string
}

/**
user 实现接口
*/
type notify interface {
	notify()
}

type notify2 interface {
	notify2()
}

/**
user 指针实现了 notify 接口
*/
func (u *user) notify() {
	fmt.Printf("notify to user %s n",u.name)
}

/**
user 实现了 notify 接口
*/
func (u user) notify2() {
	fmt.Printf("notify2 to user %s n",u.name)
}

/**
notify 方法,接收对数是notify 接口
*/
func notifyMethod(n notify) {
	n.notify()
}

func notifyMethod2(n notify2) {
	n.notify2()
}

func main() {
	u := user{"zhangsan","xxx@gmail.com"}

	//不能将user 类型作为 notify 类型传递给 notifyMethod 方法,user 并没有实现 notify 接口
	//notifyMethod(u)

	//这样传递才可以
	notifyMethod(&u)

	//user 实现了 notify2 接口,那么在user 或者 *user 都实现了此接口
	notifyMethod2(u)
	notifyMethod2(&u)

}
注:示例中notifyMethod 函数是多态函数,只要实现了notify 接口,那么这个函数可以针对任意实体类型来执行notify 方法,这就是多态。

4、类型嵌套接口实现
内部类型接口的实现会被自动提升到外部类型。如果外部类型也实现了相同的接口,那么就内部类型的实现就不会被提升。
示例代码:
package main

import "fmt"

/**
user 类型
*/
type user struct {
	name  string
	email string
}

/**
类型嵌套
*/
type admin struct {
	user
	level int
}

/**
接口
*/
type notify interface {
	notifyToEmail()
}

/*
*user 实现接口
 */
func (u *user) notifyToEmail() {
	fmt.Printf("send mail %s to user %s n",u.email,u.name)
}

/**
多态方法
*/
func notifyMethod(n notify) {
	n.notifyToEmail()
}

func main() {
	//创建一个admin
	a := admin{
		user:  user{"name","xxx@gmail.com"},level: 1,}
	//由于内部类型的提升,内部类型实现的接口会自动提升到外部类型。所有 *admin 类型也实现了notify 接口。
	//如果 *admin 实现notify 接口,则内部类型的实现就不会被提升
	notifyMethod(&a)
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读