看到晨梦思雨老哥写的一个go语法50问,咱总称自己很懂go,语法总不能还不过关吧,所以当即决定测一下。
https://blog.csdn.net/ma2595162349/article/details/115255041
1.使用值为 nil 的 slice、map会发生啥
slice是允许给nil slice添加值的,但是不能直接索引赋值,会提示index out of slice
map的话,不可以直接操作
2.访问 map 中的 key,需要注意啥
没什么好注意的,只要知道其实是返回两个值就好
if v, ok := m["first"]; ok {
fmt.Println(v)
}
3.string 类型的值可以修改吗
这大概牵扯到slice 的指针字段这种概念了。
老哥一个例子不错,会用避坑就好了。
// 修改字符串的错误示例
func main() {
x := "text"
x[0] = "T" // error: cannot assign to x[0]
fmt.Println(x)
}
// 修改示例
func main() {
x := "text"
xBytes := []byte(x)
xBytes[0] = 'T' // 注意此时的 T 是 rune 类型
x = string(xBytes)
fmt.Println(x) // Text
————————————————
版权声明:本文为CSDN博主「晨梦思雨」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ma2595162349/article/details/115255041
4.switch 中如何强制执行下一个 case 代码块
go中不需要case-break,可能是为了防止不必要的case穿透,但是也可以加上fallthrough强制执行
5.你是如何关闭 HTTP 的响应体的
因人而异,感觉defer用不用都无所谓,只要别忘了关就好,还有为什么推荐用defer,这里有一个tcp链接的坑,不知老哥会不会补充
resp, err := http.Get("http://www.baidu.com")
if err != nil {
return
}
defer resp.Body.Close()
6.你是否主动关闭过http连接,为啥要这样做
咱还真不怎么关注主动关闭这点,一直感觉keepalive就ok了。实际上咱也懂一些网络协议,可以简单分析一下。
KeepAlive带来的好处是可以减少HTTP连接的开销,提高性能。
KeepAlive带来的坏处当然是多客户端连接,又都长期占有连接,程序可能会消耗完 socket 描述符。
还有一点,哪边发起关闭连接,哪边会有TIME_WAIT,所以这个最好是客户端主动。
关闭的方式?
HTTP/1.1 defines the "close" connection option for the sender to signal that the connection will be closed after completion of the response. For example,
Connection: close
func main() {
req, err := http.NewRequest("GET", "http://www.baidu.com", nil)
if err != nil {
return
}
// method 1
req.Close = true
// method 2
//req.Header.Add("Connection", "close")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(b))
}
创建一个自定义配置的 HTTP transport 客户端,用来取消 HTTP 全局的复用连接。
func main() {
tr := http.Transport{DisableKeepAlives: true}
client := http.Client{Transport: &tr}
resp, err := client.Get("http://www.baidu.com")
...
}
7.解析 JSON 数据时,默认将数值当做哪种类型
说实话,老哥这有点为难人,不过我根据经验推导出是float64,答案果然是,但是还是验证一下了。
func main() {
var data = []byte(`{"age": 12}`)
var res map[string]interface{}
if err := json.Unmarshal(data, &res); err != nil {
fmt.Println(err)
}
fmt.Println(reflect.TypeOf(res["age"])) // float64
}
8.如何从 panic 中恢复
测试开发环境,我个人推荐直接panic,这也符合go的设计哲学,遇事不决,设计哲学。但是生产一定得recover捕捉啊,一个goroutine的panic也会导致整个程序挂掉。
defer func() {
if e := recover(); e != nil {
fmt.Println("recover")
}
}()
9.简短声明的变量需要注意啥
已经过24点了,有点困了,怎么才第九个,下面快速过了。
这个记住一个坑,struct的字段不能直接 :=
比如people1.age := 12 (wrong)
为什么,应该讲你在这个属于声明,而你想做的是给people1.age赋值,赋值和声明不是一回事
那为什么可以 a := 1 这里是声明加赋值,你再 a := 2 就报错了,因为声明只能一次,所以以后只能 a = 2
10.range 迭代 map是有序的吗
无序,你去看下汇编会定位到一个rand index的
11.recover的执行时机
不能直接调用,必须在 defer 函数中运行,而且不能嵌套
12.闭包错误引用同一个变量问题怎么处理
func main() {
for i := 0; i < 5; i++ {
i := i
defer func() {
println(i)
}()
}
}
func main() {
for i := 0; i < 5; i++ {
defer func(i int) {
println(i)
}(i)
}
}
13.在循环内部执行defer语句会发生啥
函数退出时延迟执行呗,还能发生啥。
defer咱就正常用好吧,这里面的坑太多,不清楚为什么很多人喜欢问defer执行顺序。
14.说出一个避免Goroutine泄露的措施
不用goroutine!这不是我说的,Davey Cheney说的,简单来讲就是不会用,水平不够咱就别用。
写完代码 go race 一下
用context设置一下cancel
尽量的咱用缓冲channel
测试环境pprof
...
15.如何跳出for select 循环
哈哈,意不意外,居然没法break,这个设计一开始也不懂,后来看了优先级select后突然明白了妙处
这里的答案是goto label 或者 break label
16.如何在切片中查找
放个截图吧
17.如何初始化带嵌套结构的结构体
就那样初始化呗,嵌套的你就当一个对象“字段”
18.切片和数组的区别
除非这种需要 a := [3]int{}, 否则直接slice,其他写法也都是slice
区别在于slice有一个数组指针,len,cap字段,还有一些扩容操作啊(这是一个小坑)
19.new和make的区别
老哥怎么也出这么题,这俩就不是一个用途,问区别有啥意思啊。
new 返回一个指针
make主要用于channel slice map的创建,困死不想多写了。
20.Printf()、Sprintf()、Fprintf()函数的区别用法是什么
有点不太想写了,老哥的问题越来越没意思了。
fmt.Println(fmt.Sprintf("hello %s", "world"))
fmt.Fprintln(os.Stderr, "error!!!")
21.说说go语言中的for循环
break 和continue正常
不过有一些坑,比如遍历map,slice,其实看汇编,长度已经确定,所以for append不会无限循环
22.Array 类型的值作为函数参数
// 数组使用值拷贝传参
func main() {
x := [3]int{1,2,3}
func(arr [3]int) {
arr[0] = 7
fmt.Println(arr) // [7 2 3]
}(x)
fmt.Println(x) // [1 2 3] // 并不是你以为的 [7 2 3]
}
// 传址会修改原数据
func main() {
x := [3]int{1,2,3}
func(arr *[3]int) {
(*arr)[0] = 7
fmt.Println(arr) // &[7 2 3]
}(&x)
fmt.Println(x) // [7 2 3]
}
23.说说go语言中的switch语句
fallthrough
24.说说go语言中有没有隐藏的this指针
没有
25.go语言中的引用类型包含哪些
map slice channel interface
26.go语言中指针运算有哪些
& * go不允许一些指针运算的,但是可以unsafe使用
26.说说go语言的main函数
主协程 mo go
27.go语言触发异常的场景有哪些
越界
空指针
除数0
panic
28.说说go语言的beego框架
烂
29.说说go语言的goconvey框架
单元测试
断言
能web ui
30.GoStub的作用是什么
打桩
31.go语言编程的好处是什么
没有好处
32.说说go语言的select机制
for-select 异步io
每个case都需要当作一个io操作
33.解释一下go语言中的静态类型声明
编译的时候用。
动态语言一时超爽
34.go的接口是什么
非侵入式
不懂泛型的码农喜欢自以为是的用interface充当泛型使用hhh
35.Go语言里面的类型断言是怎么回事
x.(type)
36.go语言中局部变量和全局变量的缺省值是什么
类型零值
37.go语言编程的好处是什么
重复了啊
38.解释一下go语言中的静态类型声明
???
39.模块化编程是怎么回事
go以文件夹为模块,千万别再用MVC那种东西了
40.Golang的方法有什么特别之处
多返回值,可以返回指针(注意内存逃逸,Rust就不允许h
41.Golang可变参数
func test(a ...interface{}) {}
42.Golang Slice的底层实现
数组指针
cap
len
43.Golang Slice的扩容机制,有什么注意点
Go 中切片扩容的策略是这样的:
首先判断,如果新申请容量大于 2 倍的旧容量,最终容量就是新申请的容量。
否则判断,如果旧切片的长度小于 1024,则最终容量就是旧容量的两倍。
否则判断,如果旧切片长度大于等于 1024,则最终容量从旧容量开始循环增加原来的 1/4 , 直到最终容量大于等于新申请的容量。
如果最终容量计算值溢出,则最终容量就是新申请容量。
!!!!!!!!!复制Slice,使用Copy(性能已经不错了)~~~~~~~~~~
44.Golang Map底层实现
底层散列表,map还是有一些复杂了,困就一个字,不写了
- JSON 标准库对 nil slice 和 空 slice 的处理是一致的吗
肯定不一致啊
46.Golang的内存模型,为什么小对象多了会造成gc压力
看下Tmalloc吧
47.Data Race问题怎么解决?能不能不加锁解决这个问题
发现问题,只能证明存在问题,不能确保解决问题和没有问题。
go test -race mypkg // 测试包
go run -race mysrc.go
48.在 range 迭代 slice 时,你怎么修改值的
通过索引改
49.nil 和 nil interface 的区别
记住一点,比较要比较类型和值,两者一个不一致,就不相等
50.select可以用于什么
清楚 异步和阻塞就ok了
怎么说呢,前面感觉还有点意思,后面就感觉差回事了。