随工作补充,可以作为代码reveiw的注意点。
不建议在循环中使用defer
闭包循环变量
for _, val := range values {
go func() {
fmt.Println(val)
}
}
正确写法:
for _, val := range values {
go func(v int) {
fmt.Println(v)
}(val)
}
需要判断指针为空
type Foo struct {
X int
}
func main() {
var p *Foo
fmt.Println(p.X) // panic
}
正确写法:
func main() {
var p *Point = new(Point)
fmt.Println(p.Abs())
}
以及在代码中要多做防御编程,需要判断指针是否为nil,否则容易panic
for range 循环是拷贝
s := []int{1, 1, 1}
for _, n := range s {
n += 1
}
fmt.Println(s) // 输出 1 1 1
解决办法:根据索引去定位修改
s := []int{1, 1, 1}
for i := range s {
s[i] += 1
}
fmt.Println(s)
同名变量的作用域
谨慎使用命名返回值
浅拷贝和深拷贝的问题
在defer中返回处理的问题
如下场景:我们会在defer 中做一些处理,但同时也需要把defer中的错误返回给上层。如果按照下面的方式,我们没法做到这一点。
func foo() error {
fmt.Println("process...")
err := error(nil)
defer func() {
if err == nil {
err = fmt.Errorf("defer error") // 假设这里报错
}
if err != nil {
fmt.Println("handle defer error")
}
}()
return err
}
输出:
image.png
改进,使用命名返回值:
func foo() (err error) {
fmt.Println("process...")
err = error(nil)
defer func() {
if err == nil {
err = fmt.Errorf("defer error") // 假设这里报错
}
if err != nil {
fmt.Println("handle defer error")
}
}()
return err
}
输出:
image.png











网友评论