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

解析:

这一题有两点需要注意:

  1. Add() 方法的返回值依然是指针类型 *Slice,所以可以循环调用方法 Add();
  2. 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 代码断行规则。