golang面试题解析
最近在很多地方看到了golang的面试题,看到了很多人对Golang的面试题心存恐惧,也是为了复习基础,我把解题的过程总结下来。 面试题1. 写出下面代码输出内容。packagemain import( "fmt" ) funcmain(){ defer_call() } funcdefer_call(){ deferfunc(){fmt.Println("打印前")}() deferfunc(){fmt.Println("打印中")}() deferfunc(){fmt.Println("打印后")}() panic("触发异常") } 考点:defer执行顺序 打印后 打印中 打印前 panic:触发异常 2. 以下代码有什么问题,说明原因。typestudentstruct{ Namestring Ageint } funcpase_student(){ m:=make(map[string]*student) stus:=[]student{ {Name:"zhou",Age:24},{Name:"li",Age:23},{Name:"wang",Age:22},} for_,stu:=rangestus{ m[stu.Name]=&stu } } 考点:foreach for_,stu:=rangestus{ stu.Age=stu.Age+10 } 也是不可行的。大家可以试试打印出来: funcpase_student(){ m:=make(map[string]*student) stus:=[]student{ {Name:"zhou",} //错误写法 for_,stu:=rangestus{ m[stu.Name]=&stu } fork,v:=rangem{ println(k,"=>",v.Name) } //正确 fori:=0;i<len(stus);i++{ m[stus[i].Name]=&stus[i] } fork,v.Name) } } 3. 下面的代码会输出什么,并说明原因funcmain(){ runtime.GOMAXPROCS(1) wg:=sync.WaitGroup{} wg.Add(20) fori:=0;i<10;i++{ gofunc(){ fmt.Println("A:",i) wg.Done() }() } fori:=0;i<10;i++{ gofunc(iint){ fmt.Println("B:",i) wg.Done() }(i) } wg.Wait() } 考点:go执行的随机性和闭包 第二个go func中i是函数参数,与外部for中的i完全是两个变量。尾部(i)将发生值拷贝,go func内部指向值拷贝地址。 4. 下面代码会输出什么?typePeoplestruct{} func(p*People)ShowA(){ fmt.Println("showA") p.ShowB() } func(p*People)ShowB(){ fmt.Println("showB") } typeTeacherstruct{ People } func(t*Teacher)ShowB(){ fmt.Println("teachershowB") } funcmain(){ t:=Teacher{} t.ShowA() } 考点:go的组合继承 showA showB 5. 下面代码会触发异常吗?请详细说明funcmain(){ runtime.GOMAXPROCS(1) int_chan:=make(chanint,1) string_chan:=make(chanstring,1) int_chan<-1 string_chan<-"hello" select{ casevalue:=<-int_chan: fmt.Println(value) casevalue:=<-string_chan: panic(value) } } 考点:select随机性
6. 下面代码输出什么?funccalc(indexstring,a,bint)int{ ret:=a+b fmt.Println(index,b,ret) returnret } funcmain(){ a:=1 b:=2 defercalc("1",calc("10",b)) a=0 defercalc("2",calc("20",b)) b=1 } 考点:defer执行顺序 10123 20022 2022 1134 7. 请写出以下输入内容funcmain(){ s:=make([]int,0) s=append(s,3) fmt.Println(s) } 考点:make默认值和append [00000123] 大家试试改为: s:=make([]int,3) fmt.Println(s)//[123] 8. 下面的代码有什么问题?typeUserAgesstruct{ agesmap[string]int sync.Mutex } func(ua*UserAges)Add(namestring,ageint){ ua.Lock() deferua.Unlock() ua.ages[name]=age } func(ua*UserAges)Get(namestring)int{ ifage,ok:=ua.ages[name];ok{ returnage } return-1 } 考点:map线程安全 func(ua*UserAges)Get(namestring)int{ ua.Lock() deferua.Unlock() ifage,ok:=ua.ages[name];ok{ returnage } return-1 } 9. 下面的迭代会有什么问题?func(set*threadSafeSet)Iter()<-chaninterface{}{ ch:=make(chaninterface{}) gofunc(){ set.RLock() forelem:=rangeset.s{ ch<-elem } close(ch) set.RUnlock() }() returnch } 考点:chan缓存池 packagemain import( "sync" "fmt" ) //下面的迭代会有什么问题? typethreadSafeSetstruct{ sync.RWMutex s[]interface{} } func(set*threadSafeSet)Iter()<-chaninterface{}{ //ch:=make(chaninterface{})//解除注释看看! ch:=make(chaninterface{},len(set.s)) gofunc(){ set.RLock() forelem,value:=rangeset.s{ ch<-elem println("Iter:",elem,value) } close(ch) set.RUnlock() }() returnch } funcmain(){ th:=threadSafeSet{ s:[]interface{}{"1","2"},} v:=<-th.Iter() fmt.Sprintf("%s%v","ch",v) } 10. 以下代码能编译过去吗?为什么?packagemain import( "fmt" ) typePeopleinterface{ Speak(string)string } typeStduentstruct{} func(stu*Stduent)Speak(thinkstring)(talkstring){ ifthink=="bitch"{ talk="Youareagoodboy" }else{ talk="hi" } return } funcmain(){ varpeoPeople=Stduent{} think:="bitch" fmt.Println(peo.Speak(think)) } 考点:golang的方法集 11. 以下代码打印出来什么内容,说出为什么。packagemain import( "fmt" ) typePeopleinterface{ Show() } typeStudentstruct{} func(stu*Student)Show(){ } funclive()People{ varstu*Student returnstu } funcmain(){ iflive()==nil{ fmt.Println("AAAAAAA") }else{ fmt.Println("BBBBBBB") } } 考点:interface内部结构 varininterface{} 另一种如题目: typePeopleinterface{ Show() } 他们的底层结构如下: typeefacestruct{//空接口 _type*_type//类型信息 dataunsafe.Pointer//指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } typeifacestruct{//带有方法的接口 tab*itab//存储type信息还有结构实现方法的集合 dataunsafe.Pointer//指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*) } type_typestruct{ sizeuintptr//类型大小 ptrdatauintptr//前缀持有所有指针的内存大小 hashuint32//数据hash值 tflagtflag alignuint8//对齐 fieldalignuint8//嵌入结构体时的对齐 kinduint8//kind有些枚举值kind等于0是无效的 alg*typeAlg//函数指针数组,类型实现的所有方法 gcdata*byte strnameOff ptrToThistypeOff } typeitabstruct{ inter*interfacetype//接口类型 _type*_type//结构类型 link*itab badint32 inhashint32 fun[1]uintptr//可变大小方法集合 } 可以看出iface比eface 中间多了一层itab结构。 itab 存储_type信息和[]fun方法集,从上面的结构我们就可得出,因为data指向了nil 并不代表interface 是nil,所以返回值并不为空,这里的fun(方法集)定义了接口的接收规则,在编译的过程中需要验证是否实现接口结果: BBBBBBB (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |