GO语言面试题(七)!老男孩GO培训价格
老男孩IT教育
常见问题
2021年7月12日 17:45
Go是一个开源的编程语言,它能让构造简单、可靠、高效的软件变得容易,并且拥有一个活跃的社区。之前为大家介绍了很多GO语言面试题,相信很多小伙伴已经收藏了,那么本文的GO语言面试题有哪些呢?千万不要错过,这些你们也需要懂。
Go是一个开源的编程语言,它能让构造简单、可靠、高效的软件变得容易,并且拥有一个活跃的社区。之前为大家介绍了很多GO语言面试题,相信很多小伙伴已经收藏了,那么本文的GO语言面试题有哪些呢?千万不要错过,这些你们也需要懂。
6、下面代码输出什么?
package main
import (
"fmt"
)
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1 //line 1
b := 2 //2
defer calc("1", a, calc("10", a, b)) //3
a = 0 //4
defer calc("2", a, calc("20", a, b)) //5
b = 1 //6
}
答:
运行结果:
10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4
解析:
在解题前需要明确两个概念:
defer是在函数末尾的return前执行,先进后执行,具体见问题1。
函数调用时 int 参数发生值拷贝。
不管代码顺序如何,defer calc func中参数b必须先计算,故会在运行到第三行时,执行calc("10",a,b)输出:10 1 2 3得到值3,将cal("1",1,3)存放到延后执执行函数队列中。
执行到第五行时,现行计算calc("20", a, b)即calc("20", 0, 2)输出:20 0 2 2得到值2,将cal("2",0,2)存放到延后执行函数队列中。
执行到末尾行,按队列先进后出原则依次执行:cal("2",0,2)、cal("1",1,3) ,依次输出:2 0 2 2、1 1 3 4 。
7、请写出以下输入内容
package main
import (
"fmt"
)
func main() {
s := make([]int, 5)
s = append(s, 1, 2, 3)
fmt.Println(s)
}
答:
运行结果:
[0 0 0 0 0 1 2 3]
解析:
make可用于初始化数组,第二个可选参数表示数组的长度。数组是不可变的。
当执行make([]int,5)时返回的是一个含义默认值(int的默认值为0)的数组:[0,0,0,0,0]。而append函数是便是在一个数组或slice后面追加新的元素,并返回一个新的数组或slice。
这里append(s,1,2,3)是在数组s的继承上追加三个新元素:1、2、3,故返回的新数组为[0 0 0 0 0 1 2 3]
8、下面的代码有什么问题?
package main
import (
"fmt"
"sync"
)
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
}
func main() {
userAges := &UserAges{
ages: make(map[string]int),
}
for i := 0; i < 10000; i++ {
go userAges.Add("oldboy", i)
go func() {
age := userAges.Get("oldboy")
fmt.Println(age)
}()
}
}
答:
在执行 Get方法时可能被panic
解析:
虽然有使用sync.Mutex做写锁,但是map是并发读写不安全的。map属于引用类型,并发读写时多个协程见是通过指针访问同一个地址,即访问共享变量,此时同时读写资源存在竞争关系。会报错误信息:“fatal error: concurrent map read and map write”。
可以在在线运行中执行,复现该问题。那么如何改善呢? 当然Go1.9新版本中将提供并发安全的map。首先需要了解两种锁的不同:
sync.Mutex互斥锁
sync.RWMutex读写锁,基于互斥锁的实现,可以加多个读锁或者一个写锁。
利用读写锁可实现对map的安全访问,在线运行改进版 。利用RWutex进行读锁。
type RWMutex
func (rw *RWMutex) Lock()
func (rw *RWMutex) RLock()
func (rw *RWMutex) RLocker() Locker
func (rw *RWMutex) RUnlock()
func (rw *RWMutex) Unlock()
正确代码:
package main
import (
"fmt"
"sync"
)
type UserAges struct {
ages map[string]int
sync.RWMutex
}
func (ua *UserAges) Add(name string, age int) {
ua.Lock()
defer ua.Unlock()
ua.ages[name] = age
}
func (ua *UserAges) Get(name string) int {
ua.Lock()
defer ua.Unlock()
if age, ok := ua.ages[name]; ok {
return age
}
return -1
}
func main() {
userAges := &UserAges{
ages: make(map[string]int),
}
for i := 0; i < 10000; i++ {
go userAges.Add("oldboy", i)
go func() {
age := userAges.Get("oldboy")
fmt.Println(age)
}()
}
}
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在使用make初始化时可附带一个可选参数来设置缓冲区。默认无缓冲,题目中便初始化的是无缓冲区的chan,这样只有写入的元素直到被读取后才能继续写入,不然就一直阻塞。
设置缓冲区大小后,写入数据时可连续写入到缓冲区中,直到缓冲区被占满。从chan中接收一次便可从缓冲区中释放一次。可以理解为chan是可以设置吞吐量的处理池。
ch := make(chan interface{}) 和 ch := make(chan interface{},1)是不一样的
无缓冲的 不仅仅是只能向 ch 通道放 一个值 而是一直要有人接收,那么ch <- elem才会继续下去,要不然就一直阻塞着,也就是说有接收者才去放,没有接收者就阻塞。
而缓冲为1则即使没有接收者也不会阻塞,因为缓冲大小是1只有当 放第二个值的时候 第一个还没被人拿走,这时候才会阻塞。
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))
}
答: 编译失败,值类型 Student{} 未实现接口People的方法,不能定义为 People类型。
解析:
考题中的 func (stu Stduent) Speak(think string) (talk string) 是表示结构类型Student的指针有提供该方法,但该方法并不属于结构类型Student的方法。因为struct是值类型。
修改方法:
定义为指针:
var peo People = &Stduent{}
方法定义在值类型上,指针类型本身是包含值类型的方法。
func (stu Stduent) Speak(think string) (talk string) {
//...
}
老男孩GO培训价格是多少?我校GO语言课程分为周末班及网络班,几千元即可学习,欢迎大家前来试听。
推荐阅读:
