常见语法题目 二
1、写出下面代码输出内容。
package main
import (
"fmt"
)
func main() {
defer_call()
}
func defer_call() {
defer func() { fmt.Println("打印前") }()
defer func() { fmt.Println("打印中") }()
defer func() { fmt.Println("打印后") }()
panic("触发异常")
}解析:
defer 关键字的实现跟go关键字很类似,不同的是它调用的是runtime.deferproc而不是runtime.newproc。
在defer出现的地方,插入了指令call runtime.deferproc,然后在函数返回之前的地方,插入指令call runtime.deferreturn。
goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式记录在表中,而在调用runtime.deferreturn的时候,则会依次从defer表中出栈并执行。
因此,题目最后输出顺序应该是defer 定义顺序的倒序。panic 错误并不能终止 defer 的执行。
2、 以下代码有什么问题,说明原因
解析:
golang 的 for ... range 语法中,stu 变量会被复用,每次循环会将集合中的值复制给这个变量,因此,会导致最后m中的map中储存的都是stus最后一个student的值。
3、下面的代码会输出什么,并说明原因
解析:
这个输出结果决定来自于调度器优先调度哪个G。从runtime的源码可以看到,当创建一个G时,会优先放入到下一个调度的runnext字段上作为下一次优先调度的G。因此,最先输出的是最后创建的G,也就是9.
4、下面代码会输出什么?
解析:
输出结果为showA、showB。golang 语言中没有继承概念,只有组合,也没有虚方法,更没有重载。因此,*Teacher 的 ShowB 不会覆写被组合的 People 的方法。
5、下面代码会触发异常吗?请详细说明
解析:
结果是随机执行。golang 在多个case 可读的时候会公平的选中一个执行。
6、下面代码输出什么?
解析:
输出结果为:
defer 在定义的时候会计算好调用函数的参数,所以会优先输出10、20 两个参数。然后根据定义的顺序倒序执行。
7、请写出以下输入内容
解析:
输出为 0 0 0 0 0 1 2 3。
make 在初始化切片时指定了长度,所以追加数据时会从len(s) 位置开始填充数据。
8、下面的代码有什么问题?
解析:
在执行 Get方法时可能被panic。
虽然有使用sync.Mutex做写锁,但是map是并发读写不安全的。map属于引用类型,并发读写时多个协程见是通过指针访问同一个地址,即访问共享变量,此时同时读写资源存在竞争关系。会报错误信息:“fatal error: concurrent map read and map write”。
因此,在 Get 中也需要加锁,因为这里只是读,建议使用读写锁 sync.RWMutex。
9、下面的迭代会有什么问题?
解析:
默认情况下 make 初始化的 channel 是无缓冲的,也就是在迭代写时会阻塞。
10、以下代码能编译过去吗?为什么?
解析:
编译失败,值类型 Student{} 未实现接口People的方法,不能定义为 People类型。
在 golang 语言中,Student 和 *Student 是两种类型,第一个是表示 Student 本身,第二个是指向 Student 的指针。
11、以下代码打印出来什么内容,说出为什么。。。
解析:
跟上一题一样,不同的是*Student 的定义后本身没有初始化值,所以 *Student 是 nil的,但是*Student 实现了 People 接口,接口不为 nil。