七叶笔记 » golang编程 » Golang新手可能会踩的10个坑初级篇

Golang新手可能会踩的10个坑初级篇

1.左大括号 { 不能单独放一行

在其他大多数语言中,{ 的位置你自行决定。Go比较特别,遵守分号注入规则(automatic semicolon injection):编译器会在每行代码尾部特定分隔符后加;来分隔多条语句,比如会在 ) 后加分号:

 // 错误示例
func main()                    
{
    println("www.topgoer.com是个不错的go语言中文文档")
}

// 等效于
func main();    // 无函数体                    
{
    println("hello world")
}
  
     ./main.go: missing function body
    ./main.go: syntax error: unexpected semicolon or newline before {
  
 // 正确示例
func main() {
    println("www.topgoer.com是个不错的go语言中文文档")
}
  

2.未使用的变量

如果在函数体代码中有未使用的变量,则无法通过编译,不过全局变量声明但不使用是可以的。即使变量声明后为变量赋值,依旧无法通过编译,需在某处使用它:

 // 错误示例
var gvar int     // 全局变量,声明不使用也可以

func main() {
    var one int     // error: one declared and not used
    two := 2    // error: two declared and not used
    var three int    // error: three declared and not used
    three = 3        
}


// 正确示例
// 可以直接注释或移除未使用的变量
func main() {
    var one int
    _ = one

    two := 2
    println(two)

    var three int
    one = three

    var four int
    four = four
}
  

3.未使用的 import

如果你 import一个包,但包中的变量、函数、接口和结构体一个都没有用到的话,将编译失败。可以使用 _下划线符号作为别名来忽略导入的包,从而避免编译错误,这只会执行 package 的 init()

 // 错误示例
import (
    "fmt"    // imported and not used: "fmt"
    "log"    // imported and not used: "log"
    "time"    // imported and not used: "time"
)

func main() {
}


// 正确示例
// 可以使用 goimports 工具来注释或移除未使用到的包
import (
    _ "fmt"
    "log"
    "time"
)

func main() {
    _ = log.Println
    _ = time.Now
}
  

4.简短声明的变量只能在函数内部使用

 // 错误示例
myvar := 1    // syntax error: non-declaration statement outside function body
func main() {
}


// 正确示例
var  myvar = 1
func main() {
}
  

5.使用简短声明来重复声明变量

不能用简短声明方式来单独为一个变量重复声明,:=左侧至少有一个新变量,才允许多变量的重复声明:

 // 错误示例
func main() {  
    one := 0
    one := 1 // error: no new variables on left side of :=
}


// 正确示例
func main() {
    one := 0
    one, two := 1, 2    // two 是新变量,允许 one 的重复声明。比如 error 处理经常用同名变量 err
    one, two = two, one    // 交换两个变量值的简写
}
  

6.不能使用简短声明来设置字段的值

struct 的变量字段不能使用 := 来赋值以使用预定义的变量来避免解决:

 // 错误示例
type info struct {
    result int
}

func work() (int, error) {
    return 3, nil
}

func main() {
    var data info
    data.result, err := work()    // error: non-name data.result on left side of :=
    fmt.Printf("info: %+v\n", data)
}


// 正确示例
func main() {
    var data info
    var err error    // err 需要预声明

    data.result, err = work()
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("info: %+v\n", data)
}
  

7.不小心覆盖了变量

对从动态语言转过来的开发者来说,简短声明很好用,这可能会让人误会 := 是一个赋值操作符。如果你在新的代码块中像下边这样误用了 :=,编译不会报错,但是变量不会按你的预期工作:

 func main() {
    x := 1
    println(x)        // 1
    {
        println(x)    // 1
        x := 2
        println(x)    // 2    // 新的 x 变量的作用域只在代码块内部
    }
    println(x)        // 1
}
  

这是 Go 开发者常犯的错,而且不易被发现。可使用 vet工具来诊断这种变量覆盖,Go 默认不做覆盖检查,添加 -shadow 选项来启用:

     > go tool vet -shadow main.go
    main.go:9: declaration of "x" shadows declaration at main.go:5
  

注意 vet 不会报告全部被覆盖的变量,可以使用 go-nyet 来做进一步的检测:

     > $GOPATH/bin/go-nyet main.go
    main.go:10:3:Shadowing variable `x`
  

8.显式类型的变量无法使用 nil 来初始化

nil 是 interface、function、pointer、map、slice 和 channel 类型变量的默认初始值。但声明时不指定类型,编译器也无法推断出变量的具体类型。

 // 错误示例
func main() {
    var x = nil    // error: use of untyped nil
    _ = x
}


// 正确示例
func main() {
    var x interface{} = nil
    _ = x
}
  

9.直接使用值为 nil 的 slice、map

允许对值为 nil 的 slice 添加元素,但对值为 nil 的 map添加元素则会造成运行时 panic

 // map 错误示例
func main() {
    var m map[string]int
    m["one"] = 1        // error: panic: assignment to entry in nil map
    // m := make(map[string]int)// map 的正确声明,分配了实际的内存
}    


// slice 正确示例
func main() {
    var s []int
    s = append(s, 1)
}
  

10.map 容量

在创建 map 类型的变量时可以指定容量,但不能像 slice 一样使用 cap() 来检测分配空间的大小:

 // 错误示例
func main() {
    m := make(map[string]int, 99)
    println(cap(m))     // error: invalid argument m1 (type map[string]int) for cap  
}  

相关文章