zoukankan      html  css  js  c++  java
  • Go接口

    接口 Demo

    package main
    
    import "fmt"
    
    // Person 接口类型
    type Person interface {
    	getName() string // 不带参数、返回值为 string 的方法
    } // 任何实现了方法 getName() 的类型,就说它实现了接口 Person
    
    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())
    	fmt.Println(tea.getName())
    }
    

    接口内部实现源码

    // https://github.com/golang/go/blob/master/src/runtime/runtime2.go#L203
    // iface 结构体表示非空接口:
    type iface struct {
    	tab  *itab
    	data unsafe.Pointer
    }
    
    // https://github.com/golang/go/blob/master/src/runtime/runtime2.go#L837:1
    // 非空接口的类型信息
    type itab struct {
    	inter *interfacetype // 接口定义的类型信息
    	_type *_type // 接口实际指向值的类型信息
    	hash  uint32 // copy of _type.hash. Used for type switches.
    	_     [4]byte
    	fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.接口方法实现列表,即函数地址列表,按字典序排序
    }
    
    // https://github.com/golang/go/blob/master/src/runtime/type.go#L359
    // 接口的方法声明 
    type imethod struct {
    	name nameOff // 方法名
    	ityp typeOff  // 描述方法参数返回值等细节
    }
    
    // 非空接口类型,接口定义,包路径等。
    type interfacetype struct {
    	typ     _type
    	pkgpath name
    	mhdr    []imethod // 接口方法声明列表,按字典序排序
    }
    

    非空接口(iface)本身除了可以容纳满足其接口的对象之外,还需要保存其接口的方法,因此除了data字段,iface通过tab字段描述非空接口的细节,包括接口方法定义,接口方法实现地址,接口所指类型等。

    iface是非空接口的实现,而不是类型定义,iface的真正类型为interfacetype,其第一个字段仍然为描述其自身类型的_type字段。

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

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

    指针方法值方法

    接口实现的两种方法,上面的 Demo 使用的是 值接收者(Value Receiver) 来实现接口。
    下面使用 指针接收者(Pointer Receiver) 来实现接口。

    首先了解下 Go 中的指针:

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

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

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

    在 Go 中指针的操作

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

    在函数接收者,可以使用指针方法和值方法。

    区别在于:

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

    Demo

    package main
    import "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 方法。


    学习参考:

  • 相关阅读:
    【BIGEMAP一键离线地图服务】
    android 应用签名的作用
    UniPush使用指南
    Android平台云端打包证书使用说明
    Android平台签名证书(.keystore)生成指南
    时序数据库技术体系-时序数据存储模型设计(原理)
    时序数据库技术体系 – 初识InfluxDB(原理)
    Influxdb原理详解
    jquery.easing 和 jquery.transit 动画插件的使用
    vue 移动端日期选择组件 vue-mobile-calendar
  • 原文地址:https://www.cnblogs.com/custer/p/13745437.html
Copyright © 2011-2022 走看看