go一千零一问是对go学习、面试相关问题进行总结梳理以及原理剖析,是一个正在积累的系列。一千零一问并不是真的1001个问题而是一个概数。

1.make和new的区别

  • make 初始化go内置数据结构:slice, map, chan,并且返回的就是类型本身而不是指针
  • new根据传入的类型分配内存空间且初始化零值,并返回指向这片内存空间的指针

共同点:都能分配内存。

区别:make只能作用于go内置的slice,map,chan三种类型且返回的类型就是传递进去的类型本身。new可以作用于任意类型且返回类型是指针(指针指向分配的内存空间),初始化了对应类型的零值。

为什么make不返回指针?

因为go内置类型slice,map,chan本身就是引用类型,内置结构其实有指针,所以并不需要返回指针。

2.函数调用需要传入结构体时,传指针还是值?怎么区分什么时候用哪种?

首先,go里面没有引用类型,所有的函数传递都是值传递,但是像slice,map,channel由于其内置结构里存在指针,因此传递以上类型会被修改原先数据。

  • 传值情况:不想改变原来数据,只需要数据进行使用。
  • 传指针情况:想要改变原来数据 或者 想要高效率,则传递指针更高效。

3. nil切片(nil slice)和空切片(empty slice)有什么不同?

由于slice内置结构存在指针,因此不同的是指针是否被开辟空间

  • nil slice 完全就是空未被初始化,内置指针数组未开辟空间,则 nil slice == nil 成立
  • empty slice 可以理解为空数据,已经开辟内存空间,内置指针数组已经开辟空间有指向内存地址,empty slice == nil 不成立,判空需要用 len(empty slice) == 0

基础结构

nil slice

empty slice

array

0

0x6736adb0

Len

0

0

Cap

0

0

与nil比较

True

False

// slice 内置结构
type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

4. 数组和slice切片有什么不同?

详情可以参考文章go的『slice』和『数组[]』区别、常见错误分析

  • 数组:数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。
  • slice:Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作 []T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。
  • 区别对比

最大区别:slice长度可变

区别对比

数组

slice

长度

固定

可变

元素类型

单一且固定

单一且固定

构成部分

一系列元素

指针、长度(len)、和容量(cap)(底层引用一个数组对象)

指针指向

指向数组的第一个元素地址

指向第一个slice元素对应的底层数组元素的地址, 要注意的是slice的第一个元素并不一定就是数组的第一个元素

初始化

默认值是零值,需要初始化长度

默认值是零值,不需要初始化长度

5. nil map和空map 有何不同?

nil map和空map基本一致,在操作上又不同

  • 都可以读取值,但是都是空值
  • 空map可以赋值,nil map不可以
  • 虽然都是空的,但是也可以使用delete进行删除操作(早期的go不支持nil map的删除)

6. 怎么判断map是否有(存在)值?

// 创建空map
m := map[string]int{}
value, ok := m["1"]
// 此处 ok 是判断是否存在值,次数不存在因此 ok 为false。value获取到对应类型的默认零值,此处为0

7. 如何停止一个正在运行的goroutine?

传入一个信号channel即可,一般传入context,也可以根据需要传递不同的channel。

go func() {
    for {
        select {
        case <-ctx.Done:
          return
        case <-quit:
            return
        default:
            // …
     }
  }
}()

8. 如何判断一个channel已经关闭?

ch := make(chan int)
close(ch)
value, isClose := <-chan
// 此处 isClose 将获取到channel是否关闭的状态,此处已经关闭因此获取到的是false
// 可以从已经关闭的channel获取到值,是对应类型的默认零值

9. 使用 channel 的一些注意事项

  • 使用完要及时关闭,即 close(channel)
  • 不能向已经关闭的channel写数据,会panic
  • 可以从已经关闭的channel读取数据,但是读取到的是对应类型的零值

10. select 用过吗?一般用来做什么?

go的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作每个case语句里必须是一个IO操作,确切的说,应该是一个面向channel的IO操作。

select {
case <-ch:
  // ...
}

结尾

go一千零一问是一个正在积累的系列,旨在提供go学习相关、go面试、go原理解析以及go相关库等使用。希望大家多多支持多多点赞👍🏻和分享,让go一千零一问可以更加丰富!
本期针对go基础部分10个面试题先进行了讲解,第二期继续对go基础部分面试题进行讲解。