GoLang之interface

编程入门 行业动态 更新时间:2024-10-13 20:18:05

<a href=https://www.elefans.com/category/jswz/34/1769831.html style=GoLang之interface"/>

GoLang之interface

文章目录

  • GoLang之interface
    • 1.interface的赋值问题
    • 2. interface的内部构造(非空接口iface情况)
      • 空接口eface
      • 非空接口iface
    • 3. interface内部构造(空接口eface情况)
    • 4.inteface{}与*interface{}
    • 5.面试题

GoLang之interface

1.interface的赋值问题

以下代码能编译过去吗?为什么?

test12.go

package mainimport ("fmt"
)type People interface {Speak(string) string
}type Student struct{}func (stu *Student) Speak(think string) (talk string) {if think == "love" {talk = "You are a good boy"} else {talk = "hi"}return
}func main() {var peo People = Student{}//在这里编译报错think := "love"fmt.Println(peo.Speak(think))
}

继承与多态的特点

在golang中对多态的特点体现从语法上并不是很明显。

我们知道发生多态的几个要素:

1、有interface接口,并且有接口定义的方法。

2、有子类去重写interface的接口。

3、有父类指针指向子类的具体对象

那么,满足上述3个条件,就可以产生多态效果,就是,父类指针可以调用子类的具体方法。

所以上述代码报错的地方在var peo People = Student{}这条语句, Student{}已经重写了父类People{}中的Speak(string) string方法,那么只需要用父类指针指向子类对象即可。

所以应该改成var peo People = &Student{} 即可编译通过。(People为interface类型,就是指针类型)

package mainimport ("fmt"
)type People interface {Speak(string) string
}type Student struct{}func (stu *Student) Speak(think string) (talk string) {if think == "love" {talk = "You are a good boy"} else {talk = "hi"}return
}func main() {var peo People = &Student{}think := "love"fmt.Println(peo.Speak(think)) //You are a good boyfmt.Println(peo)//&{}
}

2. interface的内部构造(非空接口iface情况)

指针的空值是nil
unsafe.Pointer的空值是nil
注:可以是nil的有“Type must be a pointer, channel, func, interface, map, or slice type”

func main() {var e *intfmt.Println(e) //<nil>
}
func main() {var e unsafe.Pointerfmt.Println(e) //<nil>
}

以下代码打印出来什么内容,说出为什么。

test14.go

package mainimport ("fmt"
)type People interface {Show()
}type Student struct{}func (stu *Student) Show() {}func live() People {var stu *Studentreturn stu
}func main() {fmt.Println(live())if live() == nil {fmt.Println("AAAAAAA")} else {fmt.Println("BBBBBBB")}
}

结果

<nil>
BBBBBBB

分析:

我们需要了解interface的内部结构,才能理解这个题目的含义。

interface在使用的过程中,共有两种表现形式

一种为空接口(empty interface),定义如下:

var MyInterface interface{}

另一种为非空接口(non-empty interface), 定义如下:

type MyInterface interface {function(
}

这两种interface类型分别用两种struct表示,空接口为eface, 非空接口为iface.

空接口eface

空接口eface结构,由两个属性构成,一个是类型信息_type,一个是数据信息。其数据结构声明如下:

type eface struct {      //空接口_type *_type         //类型信息data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}

_type属性:是GO语言中所有类型的公共描述,Go语言几乎所有的数据结构都可以抽象成 _type,是所有类型的公共描述,**type负责决定data应该如何解释和操作,**type的结构代码如下:

type _type struct {size       uintptr  //类型大小ptrdata    uintptr  //前缀持有所有指针的内存大小hash       uint32   //数据hash值tflag      tflagalign      uint8    //对齐fieldalign uint8    //嵌入结构体时的对齐kind       uint8    //kind 有些枚举值kind等于0是无效的alg        *typeAlg //函数指针数组,类型实现的所有方法gcdata    *bytestr       nameOffptrToThis typeOff
}

data属性: 表示指向具体的实例数据的指针,他是一个unsafe.Pointer类型,相当于一个C的万能指针void*

非空接口iface

iface 表示 non-empty interface 的数据结构,非空接口初始化的过程就是初始化一个iface类型的结构,其中data的作用同eface的相同,这里不再多加描述。

type iface struct {tab  *itabdata unsafe.Pointer
}

iface结构中最重要的是itab结构(结构如下),每一个 itab 都占 32 字节的空间。itab可以理解为pair<interface type, concrete type> 。itab里面包含了interface的一些关键信息,比如method的具体实现。

type itab struct {inter  *interfacetype   // 接口自身的元信息_type  *_type           // 具体类型的元信息link   *itabbad    int32hash   int32            // _type里也有一个同样的hash,此处多放一个是为了方便运行接口断言fun    [1]uintptr       // 函数指针,指向具体类型所实现的方法
}

其中值得注意的字段,个人理解如下:

1.interface type包含了一些关于interface本身的信息,比如package path,包含的method。这里的interfacetype是定义interface的一种抽象表示。

2.type表示具体化的类型,与eface的 type类型相同。

3.hash字段其实是对_type.hash的拷贝,它会在interface的实例化时,用于快速判断目标类型和接口中的类型是否一致。另,Go的interface的Duck-typing机制也是依赖这个字段来实现。

4.fun字段其实是一个动态大小的数组,虽然声明时是固定大小为1,但在使用时会直接通过fun指针获取其中的数据,并且不会检查数组的边界,所以该数组中保存的元素数量是不确定的。

所以,People拥有一个Show方法的,属于非空接口,People的内部定义应该是一个iface结构体

type People interface {Show()  
}  

func live() People {var stu *Studentreturn stu      
}     

stu是一个指向nil的空指针,但是最后return stu 会触发匿名变量 People = stu值拷贝动作,所以最后live()放回给上层的是一个People interface{}类型,也就是一个iface struct{}类型。 stu为nil,只是iface中的data 为nil而已。 但是iface struct{}本身并不为nil.

所以如下判断的结果为BBBBBBB

func main() {   if live() == nil {  fmt.Println("AAAAAAA")      } else {fmt.Println("BBBBBBB")}
}

var peo People定义非空接口的话,是nil;

var a interface{}定义空接口的话,也是nil;

package mainimport ("fmt"
)type People interface {Speak(string) string
}func main() {var peo Peoplefmt.Println(peo == nil) //truefmt.Println(peo)        //nilvar a interface{}fmt.Println(a == nil) //truefmt.Println(peo)      //nil
}

3. interface内部构造(空接口eface情况)

以下也等于nil

package mainimport ("fmt"
)type Student struct{}func (stu *Student) Show() {}func live() interface{} {var stu *Studentreturn stu
}func main() {fmt.Println(live())//<nil>if live() == nil {fmt.Println("AAAAAAA")} else {fmt.Println("BBBBBBB") //BBBBBBB}
}

如果返回slice的话,直接编译报错,无法进行类型转换

下面代码结果为什么?

func Foo(x interface{}) {if x == nil {fmt.Println("empty interface")return}fmt.Println("non-empty interface")
}
func main() {var p *int = nilFoo(p)
}

结果

non-empty interface

分析

不难看出,Foo()的形参x interface{}是一个空接口类型eface struct{}

在执行Foo(p)的时候,触发x interface{} = p语句,所以此时 x结构如下。

所以 x 结构体本身不为nil,而是data指针指向的p为nil。

4.inteface{}与*interface{}

ABCD中哪一行存在错误?

test15.go

type S struct {
}func f(x interface{}) {
}func g(x *interface{}) {
}func main() {s := S{}p := &sf(s) //Ag(s) //Bf(p) //Cg(p) //D
}

结果

B、D两行错误
B错误为: cannot use s (type S) as type *interface {} in argument to g:*interface {} is pointer to interface, not interfaceD错误为:cannot use p (type *S) as type *interface {} in argument to g:*interface {} is pointer to interface, not interface

看到这道题需要第一时间想到的是Golang是强类型语言,interface{}是所有golang类型的父类 函数中func f(x interface{})interface{}可以支持传入golang的任何类型,包括指针,但是函数func g(x *interface{})只能接受*interface{}

5.面试题

第一题

你觉得输出结果是什么呢?为什么?明明已经强制为nil

func main() {var v interface{}v = (*int)(nil)fmt.Println(v == nil)//false
}

答:false

第二题

你觉得输出结果是什么呢? 为什么?

Go interface 是 Go 语言中最常用的类型之一,大家用惯了 if err != nil 就很容易顺手就踩进去了。可以想想怎么解决?

func main() {var data *bytevar in interface{}fmt.Println(data, data == nil) //<nil> truefmt.Println(in, in == nil)     //<nil> truein = datafmt.Println(in, in == nil)//<nil> false
}

更多推荐

GoLang之interface

本文发布于:2024-03-14 02:22:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1735413.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:GoLang   interface

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!