Go 面试题

1.下面是否可以编译通过?不能通过是为什么

func main() {
    list := new([]int)
    list = append(list, 1)
    fmt.Println(list)
}

解析:不能通过,因为 new 函数返回到 是一个指针,而 append函数是对切片的操作,不是指针,可以修改成*list= append(*list,1).
channel 、slice、map 必须通过 make 初始化,这题也可以使用make 函数,make([]int,0),0表示初始化有 0 个元素,这样结果才会是[1],如果写成 make([]int,1),表示有一个元素了,执行结果就为[0,1],默认有一个 0 元素。

2.是否可以编译通过?如果通过,输出什么?

package main

import "fmt"

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{4, 5}
    s1 = append(s1, s2)
    fmt.Println(s1)
}

解析:不能通过,append切片时,要后面追加…,正确应该:s1 = append(s1, s2...),此时结果才会是 []int{1, 2, 3,4,5}

3.已知字符串 s=’hello’,把第一个字母变成 c

    s := "hello"
    c := []byte(s)  // 将字符串 s 转换为 []byte 类型
    c[0] = 'c'
    s = string(c)  // 再转换回 string 类型
    fmt.Printf("%s", s)// cello

4、以下代码有什么问题,说明原因

type student struct {
    Name string
    Age  int
}
func pase_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
    }
}

解答:考点 for, 与Java的foreach一样,都是使用副本的方式。所以m[stu.Name]=&stu实际上一致指向同一个指针, 最终该指针的值为遍历的最后一个struct的值拷贝,正确写法因该是:

 for i:=0;i<len(stus);i++ {
       m[stus[i].Name] = &stus[i]
    }

5.下面的代码会输出什么,并说明原因

func main() {
    runtime.GOMAXPROCS(1)
    wg := sync.WaitGroup{}
    wg.Add(20)
    for i := 0; i < 10; i++ {
         go func() {
             fmt.Println("A: ", i)
             wg.Done()
        }()
    }
    for i:= 0; i < 10; i++ {
        go func(i int) {
            fmt.Println("B: ", i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

解答:考察 go执行的随机性和闭包。谁也不知道执行后打印的顺序是什么样的,所以只能说是随机数字。 但是A:均为输出10,B:从0~9输出(顺序不定)。 第一个go func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。 故go func执行时,i的值始终是10。

第二个go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,go func内部指向值拷贝地址。

6、下面代码会触发异常吗

func main() {
    runtime.GOMAXPROCS(1)
    int_chan := make(chanint, 1)
    string_chan := make(chanstring, 1)
    int_chan <- 1
    string_chan <- "hello"
    select {
          case value := <-int_chan:
              fmt.Println(value)
          case value := <-string_chan:
              panic(value)
    }
}

解答:select会随机选择一个可用通用做收发操作。 所以代码是有肯触发异常,也有可能不会。 单个chan如果无缓冲时,将会阻塞。但结合 select可以在多个chan间等待执行。有三点原则:
1.select 中只要有一个case能return,则立刻执行。
2.当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
3.如果没有一个case能return则可以执行”default”块。

7、下面代码输出什么?

func calc(indexstring, a, bint) 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
}

解答:这道题考察 defer ,需要注意到defer执行顺序和值传递. index:1肯定是最后执行的,但是index:1的第三个参数是一个函数,所以最先被调用 calc("10",1,2)==>10,1,2,3,执行index:2时,与之前一样,需要先调用 calc("20",0,2)==>20,0,2,2 ,执行到b=1时候开始调用,index:2==>calc("2",0,2)==>2,0,2,2,最后执行 index:1==>calc("1",1,3)==>1,1,3,4.

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 3

第一道题的原因不是因为切片只能通过make初始化,new([]int)创建的切片的指针,这个切片是空的。出错是因为append只能对切片而非切片指针操作,如果上面的代码,改成这样,也是可以按预期输出的。

func main() {
    list := new([]int)
    *list = append(*list, 1)
    fmt.Println(*list)
}
1周前 评论

@JianFeng 感谢你的指错,是我理解有问题。

1周前 评论

个人观点:

  1. 一门语言编译过不过,ide等软件能告诉你。多调试几次就好。 面试问这个有点无聊。
  2. 一门好的语言应该是逻辑推理使用,不应该需要脑子记忆太多。
1周前 评论

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!