在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
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("触发异常") } 答: 输出内容为: 打印后 打印中 打印前 panic: 触发异常 解析:考察对 defer 的理解,defer 函数属延迟执行,延迟到调用者函数执行 return 命令前被执行。多个 defer 之间按 LIFO 先进后出顺序执行。 故考题中,在 Panic 触发时结束函数运行,在 return 前先依次打印:打印后、打印中、打印前 。最后由 runtime 运行时抛出打印 panic 异常信息。 需要注意的是,函数的 package main import ( "fmt" ) func main() { fmt.Println(doubleScore(0)) //0 fmt.Println(doubleScore(20.0)) //40 fmt.Println(doubleScore(50.0)) //50 } func doubleScore(source float32) (score float32) { defer func() { if score < 1 || score >= 100 { //将影响返回值 score = source } }() score = source * 2 return //或者 //return source * 2 } 该实例可以在 defer 中修改返回值 score 的值。具体参见官方文档 2、以下代码有什么问题,说明原因package main import ( "fmt" ) type student struct { Name string Age int } func pase_student() map[string]*student { m := make(map[string]*student) stus := []student{ {Name: "zhou", Age: 24}, {Name: "li", Age: 23}, {Name: "wang", Age: 22}, } for _, stu := range stus { m[stu.Name] = &stu } return m } func main() { students := pase_student() for k, v := range students { fmt.Printf("key=%s,value=%v \n", k, v) } } 答:输出的均是相同的值:&{wang 22} 解析:因为 for 遍历时,变量 var stu student for _, stu = range stus { m[stu.Name] = &stu } 修正方案,取数组中原始值的指针: for i, _ := range stus { stu:=stus[i] m[stu.Name] = &stu } 3、下面的代码会输出什么,并说明原因func main() { runtime.GOMAXPROCS(1) wg := sync.WaitGroup{} wg.Add(20) for i := 0; i < 10; i++ { go func() { fmt.Println("i: ", i) wg.Done() }() } for i := 0; i < 10; i++ { go func(i int) { fmt.Println("i: ", i) wg.Done() }(i) } wg.Wait() } 答: 将随机输出数字,但前面一个循环中并不会输出所有值。 解析:实际上第一行是否设置 CPU 为 1 都不会影响后续代码。两个 for 循环内部 go func 调用参数 第一个 go func 中 第二个 go func 中 4、下面代码会输出什么?type People struct{} func (p *People) ShowA() { fmt.Println("showA") p.ShowB() } func (p *People) ShowB() { fmt.Println("showB") } type Teacher struct { People } func (t *Teacher) ShowB() { fmt.Println("teacher showB") } func main() { t := Teacher{} t.ShowA() } 答: 将输出: showA showB 解析:Go 中没有继承! 没有继承!没有继承!是叫组合!组合!组合! 这里 People 是匿名组合 People。被组合的类型 People 所包含的方法虽然升级成了外部类型 Teacher 这个组合类型的方法,但他们的方法( 这里仍然是 People。毕竟这个 People 类型并不知道自己会被什么类型组合,当然也就无法调用方法时去使用未知的组合者 Teacher 类型的功能。 因此这里执行 t.ShowA() 时,在执行 ShowB() 时该函数的接受者是 People,而非 Teacher。具体参见官方文档 5、下面代码会触发异常吗?请详细说明func main() { runtime.GOMAXPROCS(1) int_chan := make(chan int, 1) string_chan := make(chan string, 1) int_chan <- 1 string_chan <- "hello" select { case value := <-int_chan: fmt.Println(value) case value := <-string_chan: panic(value) } } 答: 有可能触发异常,是随机事件。 解析:单个 chan 如果无缓冲时,将会阻塞。但结合
此考题中的两个 case 中的两个 chan 均能 return,则会随机执行某个 case 块。故在执行程序时,有可能执行第二个 case,触发异常。具体参见官方文档 6、下面代码输出什么?func calc(index string, a, b int) int { ret := a + b fmt.Println(index, a, b, ret) return ret } func main() { a := 1 b := 2 defer calc("1", a, calc("10", a, b)) a = 0 defer calc("2", a, calc("20", a, b)) b = 1 } 答:输出结果为: 10 1 2 3 20 0 2 2 2 0 2 2 1 1 3 4 解析:在解题前需要明确两个概念: + defer 是在函数末尾的 return 前执行,先进后执行,具体见问题1。 + 函数调用时 int 参数发生值拷贝。 不管代码顺序如何,defer calc func 中参数 b 必须先计算,故会在运行到第三行时,执行 执行到第五行时,现行计算 执行到末尾行,按队列先进后出原则依次执行: 7、请写出以下输入内容func main() { s := make([]int, 5) s = append(s, 1, 2, 3) fmt.Println(s) } 答: 将输出:[0 0 0 0 0 1 2 3] 解析:make 可用于初始化数组,第二个可选参数表示数组的长度。数组是不可变的。 当执行 这里 8、下面的代码有什么问题?type UserAges struct { ages map[string]int sync.Mutex } func (ua *UserAges) Add(name string, age int) { ua.Lock() defer ua.Unlock() ua.ages[name] = age } func (ua *UserAges) Get(name string) int { if age, ok := ua.ages[name]; ok { return age } return -1 } 答: 在执行 Get 方法时可能被 panic 解析:虽然有使用 可以在在线运行中执行,复现该问题。那么如何改善呢? 当然 Go1.9 新版本中将提供并发安全的 map。首先需要了解两种锁的不同:
利用读写锁可实现对 map 的安全访问,在线运行改进版 。利用 RWutex 进行读锁。 type RWMutex func (rw *RWMutex) Lock() func (rw *RWMutex) RLock() func (rw *RWMutex) RLocker() Locker func (rw *RWMutex) RUnlock() func (rw *RWMutex) Unlock() 9、下面的迭代会有什么问题?func (set *threadSafeSet) Iter() <-chan interface{} { ch := make(chan interface{}) go func() { set.RLock() for elem := range set.s { ch <- elem } close(ch) set.RUnlock() }() return ch } 答: 解析:chan 在使用 make 初始化时可附带一个可选参数来设置缓冲区。默认无缓冲,题目中便初始化的是无缓冲区的 chan,这样只有写入的元素直到被读取后才能继续写入,不然就一直阻塞。 设置缓冲区大小后,写入数据时可连续写入到缓冲区中,直到缓冲区被占满。从 chan 中接收一次便可从缓冲区中释放一次。可以理解为 chan 是可以设置吞吐量的处理池。 纠正一下:
10、以下代码能编译过去吗?为什么?package main import ( "fmt" ) type People interface { Speak(string) string } type Stduent struct{} func (stu *Stduent) Speak(think string) (talk string) { if think == "bitch" { talk = "You are a good boy" } else { talk = "hi" } return } func main() { var peo People = Stduent{} think := "bitch" fmt.Println(peo.Speak(think)) } 答: 编译失败,值类型 Student{} 未实现接口 People 的方法,不能定义为 People 类型。 解析:考题中的 修改方法:
摘自: https://yushuangqi.com/blog/2017/golang-mian-shi-ti-da-an-yujie-xi.html |
请发表评论