使用go语言没几天,犯过一些错误。这其中多数是因为阅读go语言文档不仔细,少数是因为语言本身的设计问题。

局部变量

Go语言是拥有作用域(在某些语言里叫程序块)的语言,并且同时它支持作用域局部变量,配合Go灵活的变量声明格式,很容易出现变量重复声明而不自知的情况。例如:

package main

import("fmt")

func main(){
    a := 3 // 外部
    if a > 2 {
        a := 4 // 内部
        fmt.Println(a)
    }
    fmt.Println(a)
}
Go

最后的运行结果是:

4
3

在if语句中,a被:=符号声明为{}内的局部变量,这使赋值4这一操作并未作用在外部的a中,这有时会在不经意间制造bug。与go不同,其它拥有类似特性的语言,通常使用更为明显的变量声明方式(如经典的int a = 4;),而不仅仅是在=前加一个冒号。

多个slice很可能共享同一个数组

首先是示例代码

package main

import (
    "fmt"
)

func main() {
    str := "this is str"

    slice0 := []byte(str)
    slice1 := slice0[:5]
    slice2 := slice0[5:]

    fmt.Println(string(slice0))
    fmt.Println(string(slice1))
    fmt.Println(string(slice2))

    slice0[0] = 'T'
    slice0[10] = 'R'

    fmt.Println("")
    fmt.Println(string(slice0))
    fmt.Println(string(slice1))
    fmt.Println(string(slice2))
}
Go

其运行结果为:

this is str
this
is str

This is stR
This
is stR

网上很多教程,将slice描述成可变长的动态数组。这显然是具有误导性的。如果我们把它看作动态数组,那么直觉上slice0、slice1、slice2是相互独立的三个结构体,但其实并不是。从结构上来讲,每个slice包含一个指向某数组的指针,以及该slice的长度和容量。以下来自《Go Slices: usage and internals》的图片很直白地说明了这一点:

我们不能忽略的是,显然地,多个slice是很可能共享同一数组的,当它们各自独享数组时,我们可以将其当作简单的动态数组去使用。可当它们共享时,将派生出的slice作为参数传递给函数,这种做法是有潜在风险的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注