八、深入Go 编程语言接口
发布日期:2021-07-01 02:08:06 浏览次数:2 分类:技术文章

本文共 3609 字,大约阅读时间需要 12 分钟。

@Author:Runsen

学习过Java,大家或多或少了解接口。接口是一种类型,它指定一个方法集,所有方法为接口类型就被认为是该接口。

文章目录

接口

在Go语言中,一个接口类型总是代表着某一种类型(即所有实现它的类型)的行为。一个接口类型的声明通常会包含关键字type、类型名称、关键字interface以及由花括号包裹的若干方法声明。go 使用 type 关键字来定义接口,接口的声明类似于结构体,使用类型别名且需要关键字 interface,语法如下。代码来源:菜鸟教程。

type Name interface {
Method1(param_list) return_type Method2(param_list) return_type ...}

go 中的接口,这个概念实际上是比较难懂的,来看一个demo:

package mainimport "fmt"type Person interface {
getName() string}type student struct {
Name string sex string}var stu = student{
"Runsen","男"}func (stu student) getName() string {
return stu.Name} // 这样student类型就实现了Person接口type teacher struct {
Name string sex string}var tea = teacher{
"Runsen","男"}func (tea teacher) getName() string{
return tea.Name} // 这样teacher类型就实现了Person接口func main() {
fmt.Println(stu.getName()) //Runsen fmt.Println(tea.getName()) //Runsen}

上面的代码定义了接口类型 Person ,接口中包含了一个不带参数、返回值为 string的方法 getName()。任何实现了方法 getName() 的类型 student和teacher,我们就说它实现了接口 Person 。

接口内部实现

接口内部的实现:

type iface struce{
tab *iTable data unsafe.Pointer}

接口结构是包含两个字段的数据结构,第一个包含一个指向内部表的指针,这个内部表叫做iTable,包含子所存储的值的类型信息。iTable包含了已存储的值的类型信息已经值关联的一组方法。第二个字段指向存储值的指针,指向赋值的这个对象。

从内部实现来看,接口本身也是一种结构类型,只是编译器会对其做很多的限制。

  • 不能有自己的字段
  • 不能定义自己的方法
  • 只能声明方法,不能实现
  • 可嵌入其他接口类型

这些注意点和Java的接口完全一样。

指针方法值方法

实现接口有两种方法。上面我们都是使用值接受者(Value Receiver)来实现接口的。我们同样可以使用指针接受者(Pointer Receiver)来实现接口。

在此之前,我们需要了解下指针。

指针是存储变量内存地址的变量,表达了这个变量在内存存储的位置。就像我们常说:指针指向了变量。

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

package mainimport "fmt"func main() {
var a int = 1 fmt.Printf("变量的地址: %x\n", &a) // 变量的地址: c0000140b8}

在Go语言中关于指针的操作如下所示。

package mainimport "fmt"func main() {
var a int= 1 /* 声明实际变量 */ var ip *int /* 声明指针变量 */ ip = &a /* 指针变量的存储地址 */ fmt.Printf("a 变量的地址是: %x\n", &a ) //a 变量的地址是: c0000140b8 /* 指针变量的存储地址 */ fmt.Printf("ip 变量储存的指针地址: %x\n", ip ) //ip 变量储存的指针地址: c0000140b8 /* 使用指针访问值 */ fmt.Printf("*ip 变量的值: %d\n", *ip ) //*ip 变量的值: 1}

在函数接收者,可以使用指针方法和值方法。区别在于,用指针类型作为接收者,可以在函数/方法内部修改这个接收者的数据,而用值类型作为接收者,在函数/方法内部不能修改原接收者的数据。

接收者可以是指针类型,也可以是值类型,它们到底有什么区别?一开始学Go语言的时候,我也一头雾水。看下面的例子就明白了:

package mainimport "fmt"type user struct {
name string age int}// 值的func (u user) PrintName() {
fmt.Println(u.name)}// 指针的func (u *user) PrintAge() {
fmt.Println(u.age)}func main() {
var Runsen *user // 润森是指针类型的 Runsen = &user{
"Runsen", 20} // 正常输出无误 Runsen.PrintName() // zhangsan Runsen.PrintAge() // 10 var maoli user // 毛利是值类型 maoli = user{
"Maoli", 20} // 正常输出无误 maoli.PrintName() // lisi maoli.PrintAge() // 20// 以值的方式调用 一个定义在指针类型下的方法时,会隐式的转换值到指针,例中maoli.PrintAge() 就是这样// 以指针的方式调用 一个定义在值类型下的方法时,会隐式的转换指针到值,例中Runsen.PrintName() 就是这样// 相同:无论定义在哪种类型下,都可以访问到。// 区别:只有定义在指针类型下的方法可以修改原变量的内容}

指针类型的接收者之所以需要指针,就是因为它要改变原对象的值。 在上面的例子中,调用user的SetName方法时,编译器会帮你把user的指针传递给SetName方法。

空接口

一个不包含任何方法的接口,称之为空接口,形如:interface{}。因为空接口不包含任何方法,所以任何类型都默认实现了空接口。

举个例子,fmt 包中的 Println() 函数,可以接收多种类型的值,比如:int、string、array等。为什么,因为它的形参就是接口类型,可以接收任意类型的值。

下面就是Println接口源码

func Println(a ...interface{
}) (n int, err error) {
}

空接口表示为 interface{}。由于空接口没有方法,因此所有类型都实现了空接口。

package mainimport  "fmt"func describe(i interface{
}) {
fmt.Printf("Type = %T, value = %v\n", i, i)}func main() {
s := "Hello World" describe(s) //Type = string, value = Hello World i := 1 describe(i) // Type = int, value = 1 strt := struct {
name string }{
name: "Runsen", } describe(strt) //Type = struct { name string }, value = {Runsen}}

感谢各位的阅读,文章的目的是分享对知识的理解,技术类文章我都会反复求证以求最大程度保证准确性,若文中出现明显纰漏也欢迎指出,我们一起在探讨中学习。

转载地址:https://maoli.blog.csdn.net/article/details/108022136 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Ai写的文章会死掉至少90%的创作者,作为图文自媒体,如何破局?
下一篇:五十八、2020美赛C题的思路以及个人Python的解法

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月24日 07时53分09秒