开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
今天来学习下Go常见的习题问题(十一),也是面试中可能会遇到的,让我们来一起学习吧~
for range
观察下列代码,判断输出的结果是什么?为什么?
type Foo struct {
bar string
}
func main() {
s1 := []Foo{
{"A"},
{"B"},
{"C"},
}
s2 := make([]*Foo, len(s1))
for i, value := range s1 {
s2[i] = &value
}
fmt.Println(s1[0], s1[1], s1[2])
fmt.Println(s2[0], s2[1], s2[2])
}
答案:
{A} {B} {C}
&{C} &{C} &{C}
这里主要涉及range的知识点,通过短变量声明的形式,i,value的值每次循环都会被重用,而不是重新声明,说明最后一次赋值会覆盖掉第一次的值,那么在对s进行赋值的时候,都是填充的是value临时变量的地址,最后一次循环中value的值被赋值为{C},所以最后输出3个一样的&{C}
map delete
观察下列代码,判断输出结果并说明原因?
func main() {
var m = map[string]int{
"A": 21,
"B": 22,
"C": 23,
}
counter := 0
for k, v := range m {
if counter == 0 {
delete(m, "A")
}
counter++
fmt.Println(k, v)
}
fmt.Println("counter is ", counter)
}
答案:因为map遍历是无序的,所以可能的输出结果会有两种情况,一个是先删掉A,另一个则是后删掉,还有就是go中的map是以数组的形式进行存储,所以可以在遍历的过程进行删除操作,for循环其实是对每个数组进行迭代,判断每个uint8位置,,每个数组会存储八个KV的键值对,删除也不是直接清空,而是在将标志位设置为empty
协程
关于协程,下面说法正确的是?
- 协程和线程都可以实现程序的并发执行;
- 线程比协程更轻量级;
- 协程不存在死锁问题;
- 通过 channel 来进行协程间的通信;
答案:第一个和第四个是正确的,协程比线程更轻量级,协程也会存在死锁问题
循环语句
关于循环语句,下面说法正确的是?
- 循环语句既支持 for 关键字,也支持 while 和 do-while;
- 关键字 for 的基本使用方法与 C/C++ 中没有任何差异;
- for 循环支持 continue 和 break 来控制循环,但是它提供了一个更高级的 break,可以选择中断哪一个循环;
- for 循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量;
答案:第三个和第四个是正确的,break 语句可以在后面添加标签,表示退出某个标签对应的代码块,标签要求定义在对应的for、switch 和 select 的代码块上,平行赋值的例子如:for i, j := 1, 10; i < j; i, j = i+1, j+1 {代码块}
多重赋值
观察下列代码,判断输出结果是什么?并说明原因?
func main() {
i := 1
s := []string{"A", "B", "C"}
i, s[i-1] = 2, "Q"
fmt.Printf("s: %v \n", s)
}
答案:Q B C,这里涉及到多重赋值的两个操作,
- 先要计算等号左边的索引表达式和取址表达式
- 再计算等号右边的表达式
- 最后赋值
所以这道题,会先计算 s[i-1],等号右边是两个表达式是常量,所以赋值运算等同于
i, s[0] = 2, “Q”
总结
今天浅谈了Go的习题(十一),主要介绍了GO面试中会出现的问题,接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!