zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Golang M 2023 2 theory

Golang 2023
2023-09-11 14:14:56 时间

topic

1 go struct 能不能比较

因为是强类型语言,所以不同类型的结构不能作比较,但是同一类型的实例值是可以比较的,实例不可以比较,因为是指针类型。

2 go defer(for defer),先进后出,后进先出

在这里插入图片描述

3 select 可以用于什么,常用语 gorotine 的完美退出

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

4 context 包的用途

Context 通常被译作上下文,它是一个比较抽象的概念,其本质,是【上下上下】存在上下层的传递,上会把内容传递给下。

在Go语言中,程序单元也就指的是Goroutine。

5 主协程如何等其余协程完再操作

使用 channel进行通信,context,select。

6 slice,len,cap,共享,扩容

append 函数,因为 slice 底层数据结构是,由数组、len、cap组成,所以,在使用 append 扩容时,会查看数组后面有没有连续内存快,有就在后面添加,没有就重新生成一个大的素组。

7 map 如何顺序读取

map不能顺序读取,是因为他是无序的,想要有序读取,首先的解决的问题就是,把 key 变为有序,所以可以把 key 放入切片,对切片进行排序,遍历切片,通过 key 取值。

8 实现消息队列(多生产者,多消费者)

使用切片加锁可以实现

9 大文件排序

归并排序,分而治之,拆分为小文件,在排序。

10 简短声明的变量需要注意啥

  • 简短声明的变量只能在函数内部使用
  • struct 的变量字段不能使用 := 来赋值
  • 不能用简短声明方式来单独为一个变量重复声明,:= 左侧至少有一个新变量,才允许多变量的重复声明。

11 range 迭代 map 是有序的吗?

无序的。

Go 的运行时是有意打乱迭代顺序的,所以你得到的迭代结果可能不一致。但也并不总会打乱,得到连续相同的 5 个迭代结果也是可能的。

12 切片和数组的区别

数组是具有固定长度,且拥有零个或者多个,相同数据类型元素的序列。

数组的长度是数组类型的一部分,所以 [3]int[4]int 是两种不同的数组类型。

数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变;数组是值传递。

数组是内置类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。

在初始化后长度是固定的,无法修改其长度。

当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数 len(array) 获取其长度。数组定义:

var array [10]int
var array =[5]int{1,2,3,4,5}

切片表示一个拥有相同类型元素的可变长度的序列。

切片是一种轻量级的数据结构,它有三个属性:

  • 指针
  • 长度
  • 容量

切片不需要指定大小;
切片是地址传递;

切片可以通过数组来初始化,也可以通过内置函数 make() 初始化 。

初始化时 len=cap,在追加元素时如果容量 cap 不足时将按 len 的 2 倍扩容。

切片定义:

var slice []type = make([]type, len)

13 new 和 make 的区别

new 的作用是初始化一个指向类型的指针 (*T) 。new 函数是内建函数,函数定义:func new(Type) *Type

使用 new 函数来分配空间。

传递给 new 函数的是一个类型,不是一个值。返回值是指向这个新分配的零值的指针。

make 的作用是为 slice,map 或 chan 初始化并返回引用 (T)。make 函数是内建函数,函数定义:

func make(Type, size IntegerType) Type;

第一个参数是一个类型,
第二个参数是长度;
返回值是一个类型。

make(T, args) 函数的目的与 new(T) 不同。

make 仅仅用于创建 Slice, Map 和 Channel,并且返回类型是 T(不是T*)的一个初始化的(不是零值)的实例。

14 Printf()、Sprintf()、Fprintf() 的区别

都是把格式好的字符串输出,只是输出的目标不一样。

  • Printf(),是把格式字符串输出到标准输出(一般是屏幕,可以重定向)。Printf() 是和标准输出文件 (stdout) 关联的,Fprintf 则没有这个限制。
  • Sprintf(),是把格式字符串输出到指定字符串中,所以参数比 printf 多一个 char* 。那就是目标字符串地址。
  • Fprintf(),是把格式字符串输出到指定文件设备中,所以参数比 printf 多一个文件指针 FILE*。主要用于文件操作。Fprintf() 是格式化输出到一个stream,通常是到文件。

*15 垃圾回收

  • 内存自动回收,不需要开发人员管理内存。
  • 开发人员专注业务实现,降低心智负担。
  • 只需要 new 分配内存,不需要释放。

16 go语言中的for循环

for 循环支持 continue 和 break 来控制循环,但是它提供了一个更高级的break,可以选择中断哪一个循环 for 循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量。

17 说说 go 语言中的 switch 语句

单个 case 中,可以出现多个结果选项。

只有在 case 中明确添加 fallthrough 关键字,才会继续执行紧跟的下一个 case。

18 说说go语言中有没有隐藏的this指针

方法施加的对象显式传递,没有被隐藏起来。

golang 的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达方法施加的对象不需要非得是指针,也不用非得叫 this。

*19 go语言中的引用类型包含哪些

数组切片、字典(map)、通道(channel)、接口(interface)。

20 go语言中指针运算有哪些

可以通过 “&” 取指针的地址;
可以通过 “*” 取指针指向的数据。

21 说说go语言的main函数

main 函数不能带参数;
main 函数不能定义返回值。
main 函数所在的包必须为 main 包;
main 函数中可以使用 flag 包来获取和解析命令行参数。

22 go语言触发异常的场景有哪些

  • 空指针解析
  • 下标越界
  • 除数为 0
  • 调用 panic 函数

23 go语言编程的好处是什么

编译和运行都很快。

在语言层级支持并行操作。

有垃圾处理器。

内置字符串和 maps。

函数是 go 语言的最基本编程单位。

24 说说go语言的select机制

select 机制用来处理异步 IO 问题。

select 机制最大的一条限制就是每个 case 语句里必须是一个 IO 操作。

golang 在语言级别支持 select 关键字。

25 模块化编程是怎么回事

模块化编程是指把一个大的程序分解成几个小的程序。这么做的目的是为了减少程序的复杂度,易于维护,并且达到最高的效率。

27 Golang Slice 的底层实现

切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象。

因为基于数组实现,所以它的底层的内存是连续分配的,效率非常高,还可以通过索引获得数据,可以迭代以及垃圾回收优化。

切片本身并不是动态数组或者数组指针。

它内部实现的数据结构通过指针引用底层数组,设定相关属性将数据读写操作限定在指定的区域内。切片本身是一个只读对象,其工作机制类似数组指针的一种封装。

切片对象非常小,是因为它是只有3个字段的数据结构:

  • 指向底层数组的指针
  • 切片的长度
  • 切片的容量

28 Golang Slice 的扩容机制,有什么注意点

Go 中切片扩容的策略是这样的:

首先判断,如果新申请容量大于 2 倍的旧容量,最终容量就是新申请的容量。否则判断,如果旧切片的长度小于 1024,则最终容量就是旧容量的两倍。

否则判断,如果旧切片长度大于等于 1024,则最终容量从旧容量开始循环增加原来的 1/4 , 直到最终容量大于等于新申请的容量。如果最终容量计算值溢出,则最终容量就是新申请容量。

情况一:原数组还有容量可以扩容(实际容量没有填充完),这种情况下,扩容以后的数组还是指向原来的数组,对一个切片的操作可能影响多个指针指向相同地址的Slice。

情况二:原来数组的容量已经达到了最大值,再想扩容, Go 默认会先开一片内存区域,把原来的值拷贝过来,然后再执行 append() 操作。这种情况丝毫不影响原数组。

要复制一个Slice,最好使用Copy函数。

29 Golang Map 底层实现

Golang 中 map 的底层实现是一个散列表,因此实现 map 的过程实际上就是实现散表的过程。

Map 的扩容:

当 Go 的 map 长度增长到大于加载因子所需的 map 长度时,Go 语言就会将产生一个新的 bucket 数组,然后把旧的 bucket 数组移到一个属性字段 oldbucket 中。

注意:

并不是立刻把旧的数组中的元素转义到新的 bucket 当中,而是,只有当访问到具体的某个 bucket 的时候,会把 bucket 中的数据转移到新的 bucket 中。

*30 JSON 标准库对 nil、slice、空、slice 的处理是一致的吗

首先 JSON 标准库对 nil、slice、空、slice 的处理是不一致。

通常错误的用法,会报数组越界的错误,因为只是声明了slice,却没有给实例化的对象。

var slice []int
slice[1] = 0

此时 slice 的值是nil,这种情况可以用于需要返回 slice 的函数,当函数出现异常的时候,保证函数依然会有 nil 的返回值。

empty slice 是指 slice 不为 nil,但是 slice 没有值,slice 的底层的空间是空的,此时的定义如下:

slice := make([]int,0)
slice := []int{}

当我们查询或者处理一个空的列表的时候,这非常有用,它会告诉我们返回的是一个列表,但是列表内没有任何值。

总之,nil slice 和 empty slice是不同的东西,需要我们加以区分的。