欢迎光临散文网 会员登陆 & 注册

Go语言面试题

2023-04-12 12:00 作者:诸葛孔明瑾  | 我要投稿

1、Go⾃动垃圾收集明显⽐ Java 或 Python 更有效,为什么

        并不是绝对,但是Java和Python的垃圾收集器通常会暂停应用程序的执行,以便进行垃圾收集,而go和程序同时执行的

2、切片定义的几种方式

  • 基本定义:list := []int{1, 2, 3, 4, 5, 6, 7, 8}

  • 使用make()函数来创建一个切片时,需要指定切片的长度和容量,因为make()函数需要至少一个参数来指定切片的长度。如果省略第二个参数,则默认长度和容量相等。

    • 正确定义:make([]int, length)make([]int, length, capacity)

    • 错误示例s := make([]int) 

    3、对于一个nil的channel,例如:var ch chan Type,任何发送或接收操作都会永远阻塞,因为nil表示该通道并未分配任何内存空间,无法进行通信。因此在使用之前需要先对其进行初始化,例如使用make()函数分配内存空间:ch := make(chan Type)

    4、Go语⾔中,常量⽆法寻址, 是不能进⾏取指针操作

    5、⽆缓冲的channel是同步的,⽽有缓冲的channel是⾮同步的;

        在Go语言中,无缓冲的channel是同步的,因为它在发送和接收操作时都会阻塞当前的goroutine,直到另一个goroutine准备好进行相反的操作,从而进行数据的同步交换。举个例子,当我们在无缓冲的通道中进行发送操作时,如果接收方没有准备好进行接收,发送操作会被阻塞,直到接收方准备好为止,反之亦然。相反,有缓冲的channel是非同步的,因为它在发送和接收操作时不会总是阻塞当前的goroutine,除非通道已满或为空。

    6、nil切片和空切片有什么区别

    nil切片是一个未分配内存空间的切片,其长度和容量均为0,表示该切片变量尚未指向任何底层数组,无指向任何实际的地址。使用nil切片时需要注意避免空指针引用, 定义一个nil切片: var s  [ ]int

    空切片是一个长度为0的切片,表示一个空集合,分配了内存,可以用于表示一个没有元素的切片,空切片是合法的切片,可以进行赋值和传参等操作,空切片有实际的地址,是个固定值     

    7、字符串转成byte数组,会发生内存拷贝吗   会

    这是因为Go语言的字符串底层实现是不可变的,即一个字符串变量在被创建后,其底层字节数组是不允许被修改的。因此,如果我们想要修改一个字符串变量的内容,就需要将其转换为一个可变的字节切片。字符串是不可变的。

    字符串转换为字节切片的函数是[]byte(str string)。这个函数会将字符串复制到新的字节数组中,因此会发生内存拷贝

    8、频繁的内存拷贝操作对性能不大友好。有没有什么办法可以在字符串转成切片的时候不用发生拷贝呢?

    在Go语言里面,通过将字符串类型 a 的地址转换为 unsafe.Pointer 类型的指针,然后再将指针转换为 *reflect.StringHeader类型的指针,就可以得到一个指向字符串底层数据结构的指针,以便在一些底层操作中使用,比如进行指针运算或进行类型转换等

(*reflect.StringHeader)(unsafe.Pointer(&a))
//字符串在go底层结构
type StringHeader struct {
    Data uintptr
    Len  int
}

//切片在go底层结构
type SliceHeader struct {
 Data uintptr
 Len  int
 Cap  int
}

    9、Goroutine和线程的区别

    1、轻量级:goroutine比线程更加轻量,goroutine所需要的内存大约2kb,所以可以在相同的硬件上创建更多的goroutine,线程需要的内存大概1mb,goroutine的销毁和创建成本比线程低的多

    2、调度:goroutine是由go语言的运行时系统进行调度的,而线程是由操作系统进行调度的,goroutine可以根据需要在不同的线程之间移动,更好的利用多核的cpu,goroutine采用的是协作式调度,但是线程采用的是抢占式调度

    3、共享内存;goroutine中,内存访问受到go语言内存模型的限制,所以goroutine共享内存的方式和线程不同

    4、错误处理:goroutine有自己独立的错误处理机制,可以在不中断程序的情况下,将错误传递给其他goroutine或者主程序,线程的错误处理通常是基于异常的,一旦异常发生,程序可能就会崩溃

    总结:goroutine和线程都可以用来实现并发,但是goroutine的轻量级、灵活的调度,内存共享方式和独立的错误处理机制使得它在处理大量并发任务时更加的高效

    10、make和new的区别

        1、make只能用来分配以及初始化类型为slice,map,chan的数据,返回的类型就是这三个类型本身(实例),而不是他们的指针类型,这三种类型本来就是引用类型,没必要返回他们的指针,而new可以分配任意类型的数据,分配返回的是指针,它指向的内存空间是连续的,并且已经被初始化为0,这个内存空间的大小由size来决定,即类型*Type

        2、make 函数会分配一段内存空间,并初始化一个通道对象。通道对象包含了一个缓冲区和一些元数据,用于协调通信和同步操作。例如,make(chan int) 会创建一个无缓冲的整型通道,并初始化一个通道对象。

    总之,make 函数会为对象分配内存空间,并将其初始化为对应类型的默认值。这个默认值可能是零值,也可能是其他值,具体取决于类型的定义。

    11、Go 语⾔是如何实现切⽚扩容的

    当切片的元素个数超过其容量时:

  • 如果原切片的容量小于1024个元素,则新的切片容量将扩大为原来的两倍。

  • 如果原切片的容量大于等于1024个元素,则新的切片容量将增加25%。






Go语言面试题的评论 (共 条)

分享到微博请遵守国家法律