151. 下面列举的是 recover() 的几种调用方式,哪些是正确的?
- A
func main() { recover() panic(1) } - B
func main() { defer recover() panic(1) } - C
func main() { defer func() { recover() }() panic(1) } - D
func main() { defer func() { defer func() { recover() }() }() panic(1) }
答:C
解析:
recover() 必须在 defer() 函数中直接调用才有效。上面其他几种情况调用都是无效的:直接调用 recover()、在 defer() 中直接调用 recover() 和 defer() 调用时多层嵌套。
152. 下面代码输出什么,请说明?
答:21
解析:
recover() 必须在 defer() 函数中调用才有效,所以第 9 行代码捕获是无效的。在调用 defer() 时,便会计算函数的参数并压入栈中,所以执行第 6 行代码时,此时便会捕获 panic(2);此后的 panic(1),会被上一层的 recover() 捕获。所以输出 21。
153. flag 是 bool 型变量,下面 if 表达式符合编码规范的是?
- A. if flag == 1
- B. if flag
- C. if flag == false
- D. if !flag
答:B C D
154. 下面的代码输出什么,请说明?
答:12
解析:
152题与之类似
155. 下面的代码输出什么?
答:0 [{0} {9}]
解析:
知识点:for-range 循环数组。
此时使用的是数组 ts 的副本,所以 t.n = 3 的赋值操作不会影响原数组。
156. 下面的代码输出什么?
答:9 [{0} {9}]
解析:
知识点:for-range 数组指针。
for-range 循环中的循环变量 t 是原数组元素的副本。如果数组元素是结构体值,则副本的字段和原数组字段是两个不同的值。
157. 下面的代码输出什么?
答:9 [{0} {9}]
解析:
知识点:for-range 切片。
for-range 切片时使用的是切片的副本,但不会复制底层数组,换句话说,此副本切片与原数组共享底层数组。
158. 下面的代码输出什么?
答:9 [{3} {9}]
解析:
知识点:for-range 切片。参考前几道题的解析,这道题的答案应该很明显。
159. 下面代码有什么问题吗?
解析:
goto 不能跳转到其他函数或者内层代码。编译报错:
160. 下面代码输出什么,请说明。
答:22222
解析:
知识点:defer()、for-range。
for-range 虽然使用的是 :=,但是 v 不会重新声明,可以打印 v 的地址验证下。
161. 关于 slice 或 map 操作,下面正确的是?
- A
var s []int s = append(s,1) - B
var m map[string]int m["one"] = 1 - C
var s []int s = make([]int, 0) s = append(s,1) - D
var m map[string]int m = make(map[string]int) m["one"] = 1
答:A C D
162. 下面代码输出什么?
答:100 110
解析:
知识点:闭包引用相同变量。
163. 关于字符串连接,下面语法正确的是?
- A. str := 'abc' + '123'
- B. str := "abc" + "123"
- C. str := '123' + "abc"
- D. fmt.Sprintf("abc%d", 123)
答:B D
解析:
知识点:单引号、双引号和字符串连接。
在 Go 语言中,双引号用来表示字符串 string,其实质是一个 byte 类型的数组,单引号表示 rune 类型。
164. 下面代码能编译通过吗?可以的话,输出什么?
答:43
165. 判断题:对变量x的取反操作是 ~x?
答:错
解析:
^
166. 下面代码输出什么,请说明原因。
答:132
解析:
这一题有两点需要注意:
- Add() 方法的返回值依然是指针类型 *Slice,所以可以循环调用方法 Add();
- defer 函数的参数(包括接收者)是在 defer 语句出现的位置做计算的,而不是在函数执行的时候计算的,所以 s.Add(1) 会先于 s.Add(3) 执行。
167. 下面的代码输出什么,请说明。
答:312
解析:
166
168. 下面的代码输出什么,请说明?
答:{5}
解析:
这道题容易忽视的点是,String() 是指针方法,而不是值方法,所以使用 Println() 输出时不会调用到 String() 方法。
可以这样修复:
169. 下面代码输出什么?
答:
解析:
知识点:闭包延迟求值。for 循环局部变量 i,匿名函数每一次使用的都是同一个变量。(说明:i 的地址,输出可能与上面的不一样)。
170. 下面的代码能编译通过吗?可以的话输出什么,请说明?
答:10x
解析:
这道题一眼看上去会输出 109876543210,其实这是错误的答案,这里不是递归。假设 main() 函数里为 f2(),外面的为 f1(),当声明 f2() 时,调用的是已经完成声明的 f1()。
看下面这段代码你应该会更容易理解一点:
171. 下面代码有什么问题,请说明?
以上代码在go1.14版本之前(不含1.14版本): for {} 独占 CPU 资源导致其他 Goroutine 饿死,
在go1.14版本之后(包含go1.14): 会打印0123456789, 并且主程会进入死循环
解析:
可以通过阻塞的方式避免 CPU 占用,修复代码:
172. 假设 x 已声明,y 未声明,下面 4 行代码哪些是正确的。错误的请说明原因?
答:2、3正确
解析:
知识点:简短变量声明。使用简短变量声明有几个需要注意的地方:
- 只能用于函数内部;
- 短变量声明语句中至少要声明一个新的变量;
173. 下面的代码有什么问题,请说明?
答:defer 语句应该放在 if() 语句后面,先判断 err,再 defer 关闭文件句柄。
解析:
修复代码:
174. 下面代码输出什么,为什么?
答:recover:1
解析:
panicrecover()
当程序 panic 时就不会往下执行,可以使用 recover() 捕获 panic 的内容。
175. 下面这段代码输出什么?
答:
解析:
知识点:类型断言,结构体嵌套。
结构体 S2 嵌套了结构体 S1,S2 自己没有实现 g() ,调用的是 S1 的 g()。
176. 下面的代码有什么问题?
解析:
协程里面,使用 wg.Add(1) 但是没有 wg.Done(),导致 panic()。
177. 关于 cap 函数适用下面哪些类型?
- A. 数组;
- B. channel;
- C. map;
- D. slice;
答:A B D
解析:
cap()
- array 返回数组的元素个数
- slice 返回slice的最大容量
- channel 返回 channel的容量
178. 下面代码输出什么?
- A. 18
- B. 5
- C. Compilation error
答:A
解析:
可变函数是指针传递
179. 关于 switch 语句,下面说法正确的是?
- A. 单个 case 中,可以出现多个结果选项;
- B. 需要使用 break 来明确退出一个 case;
- C. 只有在 case 中明确添加 fallthrought 关键字,才会继续执行紧跟的下一个 case;
- D. 条件表达式必须为常量或者整数;
答:A C
180. 下面代码能编译通过吗?可以的话,输出什么?
答:可以编译通过,输出:true
解析:
Go 代码断行规则。