go面试题
🐁下面代码中的指针p为野指针,因为返回的栈内存在函数结束时会被释放,这一说法是否正确。
答案:说法错误
golang不存在野指针,它有自己的垃圾回收和逃逸分析。go语言的自动内存管理机制使得只要还有一个指针引用一个变量,那这个变量就会在内存中得以保留,因此在Go语言函数内部返回指向本地变量的指针是安全的。
这题考查的是Go语言的变量逃逸...Go语言会通过判断引用关系,将在栈中初始化的变量,转变为到堆初始化。
🐳当函数deferDemo返回失败时,并不能destroy已create成功的资源()
答案:错误
题目问的是函数返回false的情况下,能不能释放资源
函数返回失败有3种情况:
一是第一次分配资源失败,直接返回,这时并没有分配成功的资源;
二是第一次分配资源成功,第二次分配资源失败,函数返回,第二次和第三次的资源都未成功分配,此时err不为nil,第一次分配成功的资源通过defer释放;
三是第一二次资源分配成功,第三次资源分配失败,函数返回,第一二次分配成功的资源通过defer释放;
如果第三次资源分配也成功了,则函数不会返回失败。
🐓从切片中删除一个元素,下面的算法实现正确的是
答案:D
因为追加的是一个slice而不是元素,故应该加上...。
函数 append 向 slice s 追加零值或其他 x 值,并且返回追加后的新的、与 s有相同类型的 slice。如果 s 没有足够的容量存储追加的值, append 分配一个足够大的、新的 slice 来存放原有 slice 的元素和追加的值。因此,返回的 slice 可能指向不同的底层 array。
s0 := []int{0, 0}
s1 := append(s0, 2) //追加一个元素, s1 == []int{0, 0, 2};
s2 := append(s1, 3, 5, 7) //追加多个元素, s2 == []int{0, 0, 2, 3, 5, 7};
s3 := append(s2, s0...) //追加一个 slice, s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}。注意这三个点!
🐈关于init函数
init函数可以在任何包中有0个或1个或多个;
首先初始化导入包的变量和常量,然后执行init函数,最后初始化本包的变量和常量,然后是init函数,最最后是main函数;
main函数只能在main包中有且只有一个,main包中也可以有0或1或多个init函数;
init函数和main函数都不能被显示调用;
🐝当程序运行时,如果遇到引用空指针、下标越界或显式调用panic函数等情况,则先触发panic函数的执行,然后调用延迟函数。调用者继续传递panic,因此该过程一直在调用栈中重复发生:函数停止执行,调用延迟执行函数。如果一路在延迟函数中没有recover函数的调用,则会到达该协程的起点,该协程结束,然后终止其他所有协程,其他协程的终止过程也是重复发生:函数停止执行,调用延迟执行函数。这一说法是否正确。
解答:
当内置的panic()函数调用时,外围函数或方法的执行会立即终止。然后,任何延迟执行(defer)的函数或方法都会被调用,就像其外围函数正常返回一样。最后,调用返回到该外围函数的调用者,就像该外围调用函数或方法调用了panic()一样,因此该过程一直在调用栈中重复发生:函数停止执行,调用延迟执行函数等。当到达main()函数时不再有可以返回的调用者,因此这个过程会终止,并将包含传入原始panic()函数中的值的调用栈信息输出到os.Stderr。
panic需要等defer结束后才会向上传递。出现panic的时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。
🐲对于局部变量整型切片x的赋值,下面定义正确的是
答案:ACD
go语言编译器会自动在以标识符、数字字面量、字母字面量、字符串字面量、特定的关键字(break、continue、fallthrough和return)、增减操作符(++和--)、或者一个右括号、右方括号和右大括号(即)、]、})结束的非空行的末尾自动加上分号。
对于B选项,6是数字字面量,所以在6的后面会自动加上一个分号,导致编译出错。
对于D选项,gofmt会自动把6后面的“,”去掉,关掉gofmt后测试,也能通过编译,正常运行。
定义切片时,新起一行时,上一行必须是逗号或者右括号
🐙关于GoStub测试框架 ,下面说法正确的是
A、GoStub可以对全局变量打桩
B、GoStub可以对函数打桩
C、GoStub可以对类的成员方法打桩
D、GoStub可以打动态桩,比如对一个函数打桩后,多次调用该函数会有不同的行为
正确答案:ABD
GoStub框架的使用场景很多,依次为:
基本场景:为一个全局变量打桩
基本场景:为一个函数打桩
基本场景:为一个过程打桩
复合场景:由任意相同或不同的基本场景组合而成
🐰import后面的最后一个元素是包名
正确答案:错误
import后面跟的是包的路径,而不是包名;
同一个目录下可以有多个.go文件,但是只能有一个包;
使用第三方库时,先将源码编译成.a文件放到临时目录下,然后去链接这个.a文件,而不是go install安装的那个.a文件;
使用标准库时,直接链接.a文件,即使修改了源码,也不会从新编译源码;
不管使用的是标准库还是第三方库,源码都是必须存在的,即使使用的是.a文件。
🐣golang中没有隐藏的this指针,这句话的含义是()
A、方法施加的对象显式传递,没有被隐藏起来
B、golang沿袭了传统面向对象编程中的诸多概念,比如继承、虚函数和构造函数
C、golang的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达
D、方法施加的对象不需要非得是指针,也不用非得叫this
正确答案:ACD
A,方法施加的对象显式传递,指的是接收器。需要给结构体增加方法时,需要使用 func (a 结构体名) 方法名(参数列表) (返回值列表) {函数体} 这种形式,在函数体里面,调用结构体成员的时候使用的就是 a.xxx,用 c 语言的方式来解释,就是将对象作为参数传入了函数,函数调用这个参数从而访问对象的成员,当然这个函数是友联函数,可以访问任意访问权限的成员
B,golang 不存在虚函数
C,这玩意看不懂,函数实现接口那块怎么解释?这也是面向对象?至于简化,这不是很主观的词嘛?怎么可以用在客观题上。。我就觉得不简化,那怎么答案是简化呢?不懂...
D,参考 A,可以传对象,不一定要传对象指针,至于名字,喜欢可以用 this,不喜欢可以看 A,用 a/b/c,随你喜欢,go 推荐用结构体名首字母小写
🌵关于接口和类的说法,下面说法正确的是
A、一个类只需要实现了接口要求的所有函数,我们就说这个类实现了该接口
B、实现类的时候,只需要关心自己应该提供哪些方法,不用再纠结接口需要拆得多细才合理
C、类实现接口时,需要导入接口所在的包
D、接口由使用方按自身需求来定义,使用方无需关心是否有其他模块定义过类似的接口
正确答案:ABD
⛄关于同步锁,下面说法正确的是
A、当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
B、RWMutex在读锁占用的情况下,会阻止写,但不阻止读
C、RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占
D、Lock()操作需要保证有Unlock()或RUnlock()调用与之对应
正确答案:ABC
1、RWMutex.RLock()时,可以随便读。多个goroutin同时读。不能写。
2、RWMutex.Lock()时(写的时候),啥都不能干。不能读,也不能写。
A选项正确,这就是互斥锁的作用
B和C看以上两条规则
D无论是RWMutex还是Mutex,与Lock()对应的都是Unlock()
🐦对于常量定义zero(const zero = 0.0),zero是浮点型常量,这一说法是否正确。
正确答案:错误
Go语言的常量有个不同寻常之处。虽然一个常量可以有任意有一个确定的基础类型,例如int或float64,或者是类似time.Duration这样命名的基础类型,但是许多常量并没有一个明确的基础类型。编译器为这些没有明确的基础类型的数字常量提供比基础类型更高精度的算术运算;你可以认为至少有256bit的运算精度。这里有六种未明确类型的常量类型,分别是无类型的布尔型、无类型的整数、无类型的字符、无类型的浮点数、无类型的复数、无类型的字符串。
❄️关于main函数(可执行程序的执行起点),下面说法正确的是
A、main函数不能带参数
B、main函数不能定义返回值
C、main函数所在的包必须为main包
D、main函数中可以使用flag包来获取和解析命令行参数
Main函数和init函数都没有参数和返回值的定义
🍔interface{}是可以指向任意对象的Any类型,这一说法是否正确。
正确答案:正确
空接口可以接受任何类型
☕Golang支持反射,反射最常见的使用场景是做对象的序列化,这一说法是否正确。
正确答案:正确
反射最常见的使用场景是做对象的序列化(serialization,有时候也叫Marshal & Unmarshal)。例如,Go语言标准库的encoding/json、encoding/xml、encoding/gob、encoding/binary等包就大量依赖于反射功能来实现。
🎯下面关于文件操作的代码可能触发异常(如下图),这一说法是否正确。
正确答案:正确
defer应该在if后面,如果文件为空,close会崩溃
file, err := os.Open("/null")
defer func() {
err := file.Close()
if err != nil {
fmt.Println("close error: ", err)
} else {
fmt.Println("close no error")
}
}()
if err != nil {
fmt.Println("open error! ", err)
return
}
-------Ouput:-----------
open error! open /null: The system cannot find the file specified.
close error: invalid argument
🍗关于slice或map操作,下面正确的是
正确答案: A C D
Make只用来创建slice,map,channel。 其中map使用前必须初始化。 append可直接动态扩容slice,而map不行。
🪲golang中分为值类型和引用类型
值类型分别有:int系列、float系列、bool、string、数组和结构体
引用类型有:指针、slice切片、管道channel、接口interface、map、函数等
值类型的特点是:变量直接存储值,内存通常在栈中分配
引用类型的特点是:变量存储的是一个地址,这个地址对应的空间里才是真正存储的值,内存通常在堆中分配
☀️考查对 pprof 包的理解
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
在影响软件系统稳定性的因素里,我们最担心的一个问题是内存泄漏,随着系统的运行,系统消耗的内存越来越多,直到最后整个操作系统越来越慢,甚至还会导致系统崩溃。在Go语言里,我们检测内存泄漏主要依靠的是go里面的pprof包,除此之外,我们还可以使用浏览器来查看系统的实时内存信息(包括CPU、goroutine等的信息)。
🐥下面赋值正确的是
A、var x = nil
B、var x interface{} = nil
C 、var x string = nil
D、var x error = nil
正确答案: B D
Go语言中的引用类型只有五个:
切片 映射 函数 方法 通道
nil只能赋值给上面五种通道类型的变量以及指针变量。
🍁关于GetPodAction定义,下面赋值正确的是
A、var fragment Fragment = new(GetPodAction)
B、var fragment Fragment = GetPodAction
C、var fragment Fragment = &GetPodAction{}
D、var fragment Fragment = GetPodAction{}
正确答案: A C D
go中var类型既可以表示指针类型的变量,也可以表示普通变量
🐍golang中大多数数据类型都可以转化为有效的JSON文本,下面几种类型除外
A、指针
B、channel
C、complex
D、函数
正确答案: B C D
虽然指针本身不能进行序列化,但是go提供了隐式转换,表面进行的是指针序列化,内部会针对指针进行取值操作,实际还是针对的起所指的对象进行序列化
😆CGO是调用C代码模块,静态库和动态库。CGO是C语言和Go语言之间的桥梁,原则上无法直接支持C++的类。CGO不支持C++语法的根本原因是C++至今为止还没有一个二进制接口规范(ABI)。CGO只支持C语言中值类型的数据类型,所以我们是无法直接使用C++的引用参数等特性的。
😅go语言的指针不支持指针运算,指针运算包括:可以通过“&”取指针的地址、可以通过“*”取指针指向的数据
🌀下面对add函数调用正确的是
A、add(1, 2)
B、add(1, 3, 7)
C、add([]int{1, 2})
D、add([]int{1, 3, 7}...)
正确答案: A B D
🍃关于channel的特性,下面说法正确的是
A、给一个 nil channel 发送数据,造成永远阻塞
B、从一个 nil channel 接收数据,造成永远阻塞
C、给一个已经关闭的 channel 发送数据,引起 panic
D、从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
正确答案: A B C D
🐢关于函数声明,下面语法错误的是
A、func f(a, b int) (value int, err error)
B、func f(a int, b int) (value int, err error)
C、func f(a, b int) (value int, error)
D、func f(a int, b int) (int, int, error)
正确答案: C
要求返回参数要么都有变量名要么都没有,必须统一。
golang中分为值类型和引用类型
值类型分别有:int系列、float系列、bool、string、数组和结构体
引用类型有:指针、slice切片、管道channel、接口interface、map、函数等
值类型的特点是:变量直接存储值,内存通常在栈中分配
引用类型的特点是:变量存储的是一个地址,这个地址对应的空间里才是真正存储的值,内存通常在堆中分配
:squirrel:
关于异常的触发,下面说法正确的是
A、空指针解析
B、下标越界
C、除数为0
D、调用panic函数
正确答案: A B C D
空指针解析、下标越界、除数为0、调用panic函数都是会报异常的。
🌱关于go vendor,下面说法正确的是
A、基本思路是将引用的外部包的源代码放在当前工程的vendor目录下面
B、编译go代码会优先从vendor目录先寻找依赖包
C、可以指定引用某个特定版本的外部包
D、有了vendor目录后,打包当前的工程代码到其他机器的$GOPATH/src下都可以通过编译
正确答案: A B D
go vendor无法精确的引用外部包进行版本控制,不能指定引用某个特定版本的外部包;
🎏关于布尔变量b的赋值,下面错误的用法是
A、b = true
B、b = 1
C、b = bool(1)
D、b = (1 == 2)
正确答案: B C
bool类型和int类型没法强制转换
🎍关于cap函数的适用类型,下面说法正确的是
A、array
B、slice
C、map
D、channel
cap的作用
arry:返回数组的元素个数
slice:返回slice的最大容量
channel:返回channel的buffer容量