13. 【初级】 Golang不支持自动垃圾回收()

参考答案:F

 

14. 【初级】 Golang支持反射,反射最常见的使用场景是做对象的序列化()

参考答案:T

 

15. 【初级】 Golang可以复用C/C++的模块,这个功能叫Cgo()

参考答案:F

 

16. 【初级】下面代码中两个斜点之间的代码,比如json:"x",作用是X字段在从结构体实例编码到JSON数据格式的时候,使用x作为名字,这可以看作是一种重命名的方式()

17. type Position struct {

18. X int `json:"x"`

19. Y int `json:"y"`

20. Z int `json:"z"`

}

参考答案:T

 

21. 【初级】通过成员变量或函数首字母的大小写来决定其作用域()

参考答案:T

 

22. 【初级】对于常量定义zero(const zero = 0.0),zero是浮点型常量()

参考答案:F

 

23. 【初级】对变量x的取反操作是~x()

参考答案:F

 

24. 【初级】下面的程序的运行结果是xello()

25. func main() {

26. str := "hello"

27. str[0] = 'x'

28. fmt.Println(str)

}

参考答案:F

 

29. 【初级】 golang支持goto语句()

参考答案:T

 

30. 【初级】下面代码中的指针p为野指针,因为返回的栈内存在函数结束时会被释放()

31. type TimesMatcher struct {

32. base int

33. }

34. func NewTimesMatcher(base int) *TimesMatcher{

35. return &TimesMatcher{base:base}

36. }

37. func main() {

38. p := NewTimesMatcher(3)

39. ...

}

参考答案:F

 

40. 【初级】匿名函数可以直接赋值给一个变量或者直接执行()

参考答案:T

 

41. 【初级】如果调用方调用了一个具有多返回值的方法,但是却不想关心其中的某个返回值,可以简单地用一个下划线“_”来跳过这个返回值,该下划线对应的变量叫匿名变量()

参考答案:T

 

42. 【初级】在函数的多返回值中,如果有error或bool类型,则一般放在最后一个()

参考答案:T

 

43. 【初级】错误是业务过程的一部分,而异常不是()

参考答案:T

 

44. 【初级】函数执行时,如果由于panic导致了异常,则延迟函数不会执行()

参考答案:F

 

45. 【中级】当程序运行时,如果遇到引用空指针、下标越界或显式调用panic函数等情况,则先触发panic函数的执行,然后调用延迟函数。调用者继续传递panic,因此该过程一直在调用栈中重复发生:函数停止执行,调用延迟执行函数。如果一路在延迟函数中没有recover函数的调用,则会到达该携程的起点,该携程结束,然后终止其他所有携程,其他携程的终止过程也是重复发生:函数停止执行,调用延迟执行函数()

参考答案:F

 

46. 【初级】同级文件的包名不允许有多个()

参考答案:T

 

47. 【中级】可以给任意类型添加相应的方法()

参考答案:F

 

48. 【初级】 golang虽然没有显式的提供继承语法,但是通过匿名组合实现了继承()

参考答案:T

 

49. 【初级】使用for range迭代map时每次迭代的顺序可能不一样,因为map的迭代是随机的()

参考答案:T

 

50. 【初级】 switch后面可以不跟表达式()

参考答案:T

 

51. 【中级】结构体在序列化时非导出变量(以小写字母开头的变量名)不会被encode,因此在decode时这些非导出变量的值为其类型的零值()

参考答案:T

 

52. 【初级】 golang中没有构造函数的概念,对象的创建通常交由一个全局的创建函数来完成,以NewXXX来命名()

参考答案:T

 

53. 【中级】当函数deferDemo返回失败时,并不能destroy已create成功的资源()

54. func deferDemo() error {

55. err := createResource1()

56. if err != nil {

57.    return ERR_CREATE_RESOURCE1_FAILED

58. }

59. defer func() {

60.    if err != nil {
61.        destroyResource1()

62.    }

63. }()

64.  

65. err = createResource2()

66. if err != nil {

67.    return ERR_CREATE_RESOURCE2_FAILED

68. }

69. defer func() {

70.    if err != nil {
71.        destroyResource2()

72.    }

73. }()

74.  

75. err = createResource3()

76. if err != nil {

77.    return ERR_CREATE_RESOURCE3_FAILED

78. }

79. return nil

}

参考答案:F

 

80. 【中级】 channel本身必然是同时支持读写的,所以不存在单向channel()

参考答案:F

 

81. 【初级】 import后面的最后一个元素是包名()

参考答案:F

 

 

 

 

 

 

 

 

 

 

 

 

最近在很多地方看到了golang的面试题,看到了很多人对Golang的面试题心存恐惧,也是为了复习基础,我把解题的过程总结下来。

面试题

1 写出下面代码输出内容。

package main
import (   
"fmt"
)
funcmain() {
    defer_call()
}
funcdefer_call() {
    deferfunc() {fmt.Println("打印前")}()
    deferfunc() {fmt.Println("打印中")}()
    deferfunc() {fmt.Println("打印后")}()
    panic("触发异常")
}

考点:defer执行顺序
解答:
defer 是后进先出。
panic 需要等defer 结束后才会向上传递。 出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。

打印后
打印中
打印前
panic: 触发异常

2 以下代码有什么问题,说明原因。

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

考点:foreach
解答:
这样的写法初学者经常会遇到的,很危险! 与Java的foreach一样,都是使用副本的方式。所以m[stu.Name]=&stu实际上一致指向同一个指针, 最终该指针的值为遍历的最后一个struct的值拷贝。 就像想修改切片元素的属性:

for _, stu := rangestus {
    stu.Age = stu.Age+10}

也是不可行的。 大家可以试试打印出来:

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
    }    
     fork,v:=range m{        
      println(k,"=>",v.Name)
    }    
      // 正确
    for i:=0;i<len(stus);i++ {
       m[stus[i].Name] = &stus[i]
    }    
     fork,v:=range m{        
       println(k,"=>",v.Name)
    }
}

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

func main() {
    runtime.GOMAXPROCS(1)
    wg := sync.WaitGroup{}
    wg.Add(20)   for i := 0; i < 10; i++ {        
         gofunc() {
           fmt.Println("A: ", i)
           wg.Done()
        }()
    }    
        for i:= 0; i < 10; i++ {        
           gofunc(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内部指向值拷贝地址。
4 下面代码会输出什么?

type People struct{}func (p *People)ShowA() {
    fmt.Println("showA")
    p.ShowB()
}
func(p*People)ShowB() {
    fmt.Println("showB")
}
typeTeacher struct {
    People
}
func(t*Teacher)ShowB() {
    fmt.Println("teachershowB")
}
funcmain() {
    t := Teacher{}
    t.ShowA()
}

考点:go的组合继承
解答:
这是Golang的组合模式,可以实现OOP的继承。 被组合的类型People所包含的方法虽然升级成了外部类型Teacher这个组合类型的方法(一定要是匿名字段),但它们的方法(ShowA())调用时接受者并没有发生变化。 此时People类型并不知道自己会被什么类型组合,当然也就无法调用方法时去使用未知的组合者Teacher类型的功能。
showAshowB

5 下面代码会触发异常吗?请详细说明

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)
          casevalue := <-string_chan:        
          panic(value)
    }
}

考点:select随机性
解答:
select会随机选择一个可用通用做收发操作。 所以代码是有肯触发异常,也有可能不会。 单个chan如果无缓冲时,将会阻塞。但结合 select可以在多个chan间等待执行。有三点原则:

select 中只要有一个case能return,则立刻执行。
当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
如果没有一个case能return则可以执行”default”块。

6 下面代码输出什么?

funccalc(indexstring, a, bint) int {
    ret := a+ b
    fmt.Println(index,a, b, ret)
    return ret
}
funcmain() {   
      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执行顺序
解答:
这道题类似第1题 需要注意到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

10 1 2 320 0 2 22 0 2 21 1 3 4

7 请写出以下输入内容

funcmain() {    
       s := make([]int,5)
    s = append(s,1, 2, 3)
    fmt.Println(s)
}

考点:make默认值和append
解答:
make初始化是由默认值的哦,此处默认值为0

[00000123]

大家试试改为:

s := make([]int, 0)
s = append(s, 1, 2, 3)
fmt.Println(s)//[1 2 3]

8 下面的代码有什么问题?

type UserAges struct {
    ages map[string]int
    sync.Mutex
}
func(ua*UserAges)Add(name string, age int) {
    ua.Lock()  
       deferua.Unlock()
    ua.ages[name] = age
}
func(ua*UserAges)Get(name string)int {    
      ifage, ok := ua.ages[name]; ok {        
         return age
    }  
      return-1
}

考点:map线程安全
解答:
可能会出现

fatal error: concurrent mapreadandmapwrite.

修改一下看看效果

func (ua *UserAges)Get(namestring)int {
    ua.Lock()    
     deferua.Unlock()    
     ifage, ok := ua.ages[name]; ok {        
          return age
    }    
       return-1
}