一道golang中关于接口和实现的面试题

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

package main

import (
	"fmt"
)

type People interface {
    
    
	Speak(string) string
}

type Student struct{
    
    }

func (stu *Student) Speak(think string) (talk string) {
    
    
	if think == "bitch" {
    
    
		talk = "You are a good boy"
	} else {
    
    
		talk = "hi"
	}
	return
}

func main() {
    
    
	var peo People = Student{
    
    }
	think := "bitch"
	fmt.Println(peo.Speak(think))
}














答案


编译失败,值类型 `Student{}` 未实现接口`People`的方法,不能定义为 `People`类型。

在 golang 语言中,`Student` 和 `*Student` 是两种类型,第一个是表示 `Student` 本身,第二个是指向 `Student` 的指针。

如何改写?

将方法集改为值类型


type Student struct{
    
    }

// 使用值
func (stu Student) Speak(think string) (talk string) {
    
    
	if think == "bitch" {
    
    
		talk = "You are a good boy"
	} else {
    
    
		talk = "hi"
	}
	return
}

func main() {
    
    
	var peo People = Student{
    
    }
	think := "bitch"
	fmt.Println(peo.Speak(think))
}

或者, 使用指针

type Student struct{
    
    }

func (stu *Student) Speak(think string) (talk string) {
    
    
	if think == "bitch" {
    
    
		talk = "You are a good boy"
	} else {
    
    
		talk = "hi"
	}
	return
}

func main() {
    
    
	var peo People = &Student{
    
    } // 使用指针
	think := "bitch"
	fmt.Println(peo.Speak(think))
}

我们再看一道类似的题:

请问以下代码运行会输出什么? 为什么?

package main

import (
	"fmt"
)

type People interface {
    
    
	Show()
}

type Student struct{
    
    }

func (stu *Student) Show() {
    
    

}

func live() People {
    
    
	var stu *Student
	if stu == nil {
    
    
		fmt.Println("C")
	}
	return stu
}


func main() {
    
    
	p := live()
	if p == nil {
    
    
		fmt.Println("A")
	} else {
    
    
		fmt.Println("B")
	}
}

请思考,答案在下文

















答案

C
B

跟上一题一样,不同的是*Student 的定义后本身没有初始化值,所以 *Studentnil的,但是*Student 实现了 People 接口,接口不为 nil

go中的接口分为两种: 空接口带有方法的接口

type eface struct {
    
          //空接口
    _type *_type         //类型信息
    data  unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}
type iface struct {
    
          //带有方法的接口
    tab  *itab           //存储type信息还有结构实现方法的集合
    data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}
type _type struct {
    
    
    size       uintptr  //类型大小
    ptrdata    uintptr  //前缀持有所有指针的内存大小
    hash       uint32   //数据hash值
    tflag      tflag
    align      uint8    //对齐
    fieldalign uint8    //嵌入结构体时的对齐
    kind       uint8    //kind 有些枚举值kind等于0是无效的
    alg        *typeAlg //函数指针数组,类型实现的所有方法
    gcdata    *byte
    str       nameOff
    ptrToThis typeOff
}
type itab struct {
    
    
    inter  *interfacetype  //接口类型
    _type  *_type          //结构类型
    link   *itab
    bad    int32
    inhash int32
    fun    [1]uintptr      //可变大小 方法集合
}

我们将代码编译用gdb进行调试, go build -gcflags "-N -l" solution21.go

$ go build -gcflags "-N -l" solution21.go 
$ gdb solution21
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from solution21...
Loading Go Runtime support.
(gdb) l
11      type Student struct{}
12
13      func (stu *Student) Show() {
14
15      }
16
17      func live() People {
18              var stu *Student
19              if stu == nil {
20                      fmt.Println("C")
(gdb) 
21              }
22              return stu
23      }
24
25      func main() {
26              p := live()
27              if p == nil {
28                      fmt.Println("A")
29              } else {
30                      fmt.Println("B")
(gdb) 
31              }
32      }
(gdb) 
Line number 33 out of range; /home/yqq/mine/master-go/interview/6-interview-golang/solution21.go has 32 lines.
(gdb) b 27
Breakpoint 1 at 0x47e147: file /home/yqq/mine/master-go/interview/6-interview-golang/solution21.go, line 27.
(gdb) r
Starting program: /home/yqq/mine/master-go/interview/6-interview-golang/solution21 
[New LWP 24400]
[New LWP 24401]
[New LWP 24402]
[New LWP 24403]
[New LWP 24404]
C

Thread 1 "solution21" hit Breakpoint 1, main.main ()
    at /home/yqq/mine/master-go/interview/6-interview-golang/solution21.go:27
27              if p == nil {
(gdb) i locals
p = {tab = 0x4b3188 <Student,main.People>, data = 0x0}
(gdb) 

其中可以看到, p = {tab = 0x4b3188 <Student,main.People>, data = 0x0}, interface是由2部分组成的,tabdata, 当比较pnil时当然就不相等了。

我们用gdb看看下面代码

package main

import "fmt"

func main() {
    
    
	var p interface{
    
    } = nil
	if p == nil {
    
    
		fmt.Println("A")
	} else {
    
    
		fmt.Println("B")
	}

	var q interface{
    
    } = (*interface{
    
    })(nil)
	if q == nil {
    
    
		fmt.Println("C")
	} else {
    
    
		fmt.Println("D")
	}

}

go build -gcflags "-N -l" solution22.go 编译

$ gdb solution22 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from solution22...
Loading Go Runtime support.
(gdb) l
1       package main
2
3       import "fmt"
4
5       func main() {
    
    
6               var p interface{
    
    } = nil
7               if p == nil {
    
    
8                       fmt.Println("A")
9               } else {
    
    
10                      fmt.Println("B")
(gdb) 
11              }
12
13              var q interface{
    
    } = (*interface{
    
    })(nil)
14              if q == nil {
    
    
15                      fmt.Println("C")
16              } else {
    
    
17                      fmt.Println("D")
18              }
19
20      }
(gdb) b 7
Breakpoint 1 at 0x47e08c: file /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go, line 7.
(gdb) b 14
Breakpoint 2 at 0x47e109: file /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go, line 14.
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000047e08c in main.main 
                                                   at /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go:7
2       breakpoint     keep y   0x000000000047e109 in main.main 
                                                   at /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go:14
(gdb) r
Starting program: /home/yqq/mine/master-go/interview/6-interview-golang/solution22 
[New LWP 28172]
[New LWP 28173]
[New LWP 28174]
[New LWP 28175]

Thread 1 "solution22" hit Breakpoint 1, main.main ()
    at /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go:7
7               if p == nil {
    
    
(gdb) p p
$1 = {
    
    _type = 0x0, data = 0x0}
(gdb) c
Continuing.
A

Thread 1 "solution22" hit Breakpoint 2, main.main ()
    at /home/yqq/mine/master-go/interview/6-interview-golang/solution22.go:14
14              if q == nil {
    
    
(gdb) p q
$2 = {
    
    _type = 0x483360, data = 0x0}
(gdb) 

可以看到,p 打印出来的是 $1 = {_type = 0x0, data = 0x0}
q 打印出来的是 {_type = 0x483360, data = 0x0}

最后总结一下:

golang中的interface底层是由2部分组成的,即(type,data),只要其中一个不是nil, 那么,当用intefalcenil进行比较时都不相等。

猜你喜欢

转载自blog.csdn.net/yqq1997/article/details/125956924
今日推荐