浅谈Go与习题(十一)

107 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 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

image.png

协程

关于协程,下面说法正确的是?

  • 协程和线程都可以实现程序的并发执行;
  • 线程比协程更轻量级;
  • 协程不存在死锁问题;
  • 通过 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面试中会出现的问题,接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!