Go 语言
声明、类型、语句与控制结构
变量声明形式

变量声明形式

Go 语言沿袭了静态编译型语言的传统,使用变量之前需要先进行变量的声明。

var a int 32
var s string = "hello"
var i = 13
n := 17
var (
    crlf = []byte("\r\n")
    colonSpace = []byte(": ")
)

Gopher 在变量声明形式的选择上应尽量保持项目范围内的一致。

Go 语言有两类变量:

  • 包级变量:在 pkg 级别可见的变量,如果是导出变量,也可以被视为全局变量;
  • 局部变量:在函数或方法体内部声明的变量,只在内部可见。

包级变量

从声明变量时是否需要延迟初始化的角度对包级变量进行分类:

声明并同时显式初始化

var variableName = InitExpression

不带类型信息的常量表达式,会根据右值的类型来推导变量的类型。

 
```go
var a = 17
var b = 3.14

也可以显式为包级变量制定类型

// 第一种
var a int32 = 17
var b float32 = 3.14
 
// 第二种
var a = int32(17)
var b = float32(3.14)

Go 语言官方更推荐后者,因为统一了接收默认类型和显式指定类型两种声明形式。

声明但延迟初始化

声明时并不显式初始化包级变量:

var a int32
var f float32

这种形式的声明,变量的初始值为其类型的零值。

就近原则

变量声明最佳实践的一条:就近原则,即变量的声明应尽可能靠近其使用位置。

就近原则实际上是变量作用域最小化的一种实现手段。

var ErrNoCookie = errors.New("no cookie found")
 
func (r *Request) Cookie(name string) (*Cookie, error) {
    for _, cookie := range r.Cookies() {
        if cookie.Name == name {
            return cookie, nil
        }
    }
    return nil, ErrNoCookie
}

局部变量

延迟初始化

对于延迟初始化的局部变量声明,采用带有 var 关键词的声明形式:

func (r * byteRelacer) Replace(s string) string {
    var buf bytes.Buffer // 延迟分配
    for i := 0; i < len(s); i++ {
        if j := r.index(s[i:]); j >= 0 {
            buf.WriteString(r.new)
            i += j + r.oldLen - 1
        } else {
            buf.WriteByte(s[i])
        }
    }
    return buf.String()
}

另外一种常见的是声明 err,尤其是 defer 后接闭包函数需要使用 err 来判断退出状态。

func Foo() {
    var err error
    defer func() {
        if err != nil {
            ...
        }
    }()
 
    err = Bar()
    ...
}

短变量声明形式

短变量声明形式是局部变量最常用的声明形式,它的语法形式为:

a := 17
f := 3.14
s := "hello"

分支控制采用短变量声明

这种方式体现出就近原则,让变量的作用域最小化。

func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
    if wv, ok := w.(buffterWriter); ok {
        return wv.writeBuffers(v)
    }
 
    for _, b := range *v {
        nb, err := w.Write(b)
        n += int64(nb)
        if err != nil {
            v.consume(n)
            return n, err
        }
    }
    v.consume(n)
    return n, nil
}

良好的函数、方法设计讲究单一职责。如果在声明局部变量时遇到适合聚类的应用场景,也应该毫不犹豫地使用 var 块来声明多个局部变量。