Golang面试题解析
最近在很多地方看到了golang的面试题,看到了很多人对Golang的面试题心存恐惧,也是为了复习基础,我把解题的过程总结下来。 面试题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("触发异常") } 考点:defer执行顺序 打印后 打印中 打印前 panic: 触发异常 2. 以下代码有什么问题,说明原因。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 } } 考点:foreach for _,stu := range stus { stu.Age = stu.Age+10 } 也是不可行的。 大家可以试试打印出来: func pase_student() { m := make(map[string]*student) stus := []student{ {Name: "zhou",} // 错误写法 for _,stu := range stus { m[stu.Name] = &stu } for k,v:=range m{ println(k,"=>",v.Name) } // 正确 for i:=0;i<len(stus);i++ { m[stus[i].Name] = &stus[i] } for k,v.Name) } } 3. 下面的代码会输出什么,并说明原因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执行的随机性和闭包 第二个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") } type Teacher struct { People } func (t *Teacher) ShowB() { fmt.Println("teacher showB") } func main() { t := Teacher{} t.ShowA() } 考点:go的组合继承 showA showB 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) } } 考点:select随机性
6. 下面代码输出什么?func calc(index string,a,b int) int { ret := a + b fmt.Println(index,b,ret) return ret } func main() { a := 1 b := 2 defer calc("1",calc("10",b)) a = 0 defer calc("2",calc("20",b)) b = 1 } 考点:defer执行顺序 10 1 2 3 20 0 2 2 2 0 2 2 1 1 3 4 7. 请写出以下输入内容func main() { s := make([]int,5) s = append(s,3) fmt.Println(s) } 考点:make默认值和append [0 0 0 0 0 1 2 3] 大家试试改为: s := make([]int,0) s = append(s,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() 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 } 考点:map线程安全 func (ua *UserAges) Get(name string) int { ua.Lock() defer ua.Unlock() if age,ok := ua.ages[name]; ok { return age } return -1 } 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缓存池 package main import ( "sync" "fmt" ) //下面的迭代会有什么问题? type threadSafeSet struct { sync.RWMutex s []interface{} } func (set *threadSafeSet) Iter() <-chan interface{} { // ch := make(chan interface{}) // 解除注释看看! ch := make(chan interface{},len(set.s)) go func() { set.RLock() for elem,value := range set.s { ch <- elem println("Iter:",elem,value) } close(ch) set.RUnlock() }() return ch } func main() { th:=threadSafeSet{ s:[]interface{}{"1","2"},} v:=<-th.Iter() fmt.Sprintf("%s%v","ch",v) } 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)) } 考点:golang的方法集 11. 以下代码打印出来什么内容,说出为什么。package main import ( "fmt" ) type People interface { Show() } type Student struct{} func (stu *Student) Show() { } func live() People { var stu *Student return stu } func main() { if live() == nil { fmt.Println("AAAAAAA") } else { fmt.Println("BBBBBBB") } } 考点:interface内部结构 var in interface{} 另一种如题目: type People interface { Show() } 他们的底层结构如下: type eface struct { //空接口 _type *_type //类型信息 data unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } type iface struct { //带有方法的接口 tab *itab //存储type信息还有结构实现方法的集合 data unsafe.Pointer //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } type _type struct { size uintptr //类型大小 ptrdata uintptr //前缀持有所有指针的内存大小 hash uint32 //数据hash值 tflag tflag align uint8 //对齐 fieldalign uint8 //嵌入结构体时的对齐 kind uint8 //kind 有些枚举值kind等于0是无效的 alg *typeAlg //函数指针数组,类型实现的所有方法 gcdata *byte str nameOff ptrToThis typeOff } type itab struct { inter *interfacetype //接口类型 _type *_type //结构类型 link *itab bad int32 inhash int32 fun [1]uintptr //可变大小 方法集合 } 可以看出iface比eface 中间多了一层itab结构。 itab 存储_type信息和[]fun方法集,从上面的结构我们就可得出,因为data指向了nil 并不代表interface 是nil, 所以返回值并不为空,这里的fun(方法集)定义了接口的接收规则,在编译的过程中需要验证是否实现接口 结果: BBBBBBB (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |