golang面试总结2

215 阅读4分钟

如何让一个goroutine停止?

只需要监听,case中监听对应的chan

func main() {
  ch := make(chan bool)
  go func(){
    for {
       select {
         case <- ch:
         return
         default : 
         fmt.Println("linten")
       }    
    }
  }()
  ch <- true
}

如何在运行时检查变量类型?

通过反射来检查reflect.typeOf 和 reflect.valueOf
其中typeOf是的入参是interface value返回其type值,通过switchcase结合即可判断类型,在对应的case下根据valueOf接口将值转化为目标值

Go interface和struct之间的关系?

package main
import "fmt"
type AbCourseInterface interface {
   GetCourseInfo() string
}
type AiCourseStruct struct {
   Name string
}
func (aiCourse AiCourseStruct) GetCourseInfo() string {
   return aiCourse.Name
}
type BcCourseStruct struct {
   Name string
}
func (BcCourseStruct BcCourseStruct) GetCourseInfo() string {
   return BcCourseStruct.Name
}
func EchoName (obj AbCourseInterface) string {
   return obj.GetCourseInfo()
}
func main()  {
   a := AiCourseStruct{
      Name:"13",
   }
   fmt.Println(EchoName(a))
}

结果输出 13

interface定义方法A,如果结构体实现了interface的方法A,那么这是如果有方法B的入参类型是AbCourseInterface,那么当前方法调用方法B可以直接传入实现了AbCourseInterface的结构体

Go 当中同步锁有什么特点?作用是什么

mutex,分为读锁和写锁和mysql比较类似
当一个goroutine给一个key设置了读锁,那么其他的goroutine可以读到当前锁,但是不能对当前锁进行操作
当一个goroutine给一个key设置了写锁,那么其他锁将会获取不到当前锁,即不能读也不能写

Go 语言当中 Channel(通道)有什么特点,需要注意什么?

如果给一个 nil 的 channel 发送数据,会造成永远阻塞。
如果从一个 nil 的 channel 中接收数据,也会造成永久阻塞。 
给一个已经关闭的 channel 发送数据, 会引起 panic

Go 语言当中 Channel 缓冲有什么特点?

make(chan bool, 1000)
第二个参数是是否设置缓冲区
不设置缓冲区的话那么就是同步的
  不设置缓冲区,初始化一个chan,这是如果没有接收者在读区当前的chan那么往里写数据会报错
设置缓冲区的话那么就是异步的
  设置缓冲区,初始化一个chan,比如大小是2,那么在没有接收者读区的情况下往chan里面写数据超过2条就会报错

Go 语言中 cap 函数可以作用于哪些内容

cap查看数组 slice、map、chan的容量
slice的底层结构
struct    Slice
    {
        byte*    array;        // actual data
        uintgo    len;        // number of elements
        uintgo    cap;        // allocated number of elements
    };
首先slice当作参数传入函数时,会发生copy,slice1变为slice2,但是array的指针实际上是一样的,所以在方法哪对当前slice进行值修改,外层函数的值是也会被修改的
但是slice的cap和len不是指针,所以不会修改,如果需要修改的话需要在用之前加上*

map
type hmap struct {
	count     int
	flags     uint8
	B         uint8
	noverflow uint16
	hash0     uint32

	buckets    unsafe.Pointer // 当前桶大小
	oldbuckets unsafe.Pointer // 扩容时存放buckets的一半
	nevacuate  uintptr

	extra *mapextra
}

当我们make一个map字段后其实是返回的一个8个字节的指针,当前指针指向了hmap这个结构,接下来让我们看一下hmap结构中每个字段代表的具体含义:
count 代表了当前map结构的长度
flag  代表了当前map的状态,写入中还是?空闲等
B     代表了hash桶的对数 比如B是3 那么 2的三次方当前就有八个桶
noverflow 代表了当前溢出桶的数量
hash0 生成hash的种子数
buckets 指针,指向当前所有的数据桶
oldbuckets 如果map需要扩容的话,old这个指向buckets这个桶,然后让buckets去扩容(扩容1倍)
nevacuate 扩容进度
extra 代表当前溢出桶指针
接下来我们重点讲解一下buckets这个字段和extra这个字段

type bmap struct{
    tophash [8]uint8 长度为8的数组,用于定位当前key是否在这个桶里
    keys [8]keytype 
    // keytype 
    values [8]elemtype 
    // elemtype 
    overflow uintptr 
    // overflow指向下一个bmap,overflow是uintptr而不是*bmap类型,保证bmap完全不含指针,是为了减少gc,溢出桶存储到extra字段中
}

接下来我们讲解一下mapextra这个结构

type mapextra struct {
	overflow    *[]*bmap
	oldoverflow *[]*bmap
	nextOverflow *bmap
}
当1个桶的数据存满了之后,bmap的overflow会指向uintptr 而不是指针,为了防止被gc删除,所以数据就都会放到mapextra中

image.png