2.5. 使用一致的声明样式

Go 至少有六种不同的方式来声明变量

  • var x int = 1
  • var x = 1
  • var x int; x = 1
  • var x = int(1)
  • x := 1

我确信还有更多我没有想到的。 这可能是 Go 语言的设计师意识到的一个错误,但现在改变它为时已晚。 通过所有这些不同的方式来声明变量,我们如何避免每个 Go 程序员选择自己的风格?

我想就如何在程序中声明变量提出建议。 这是我尽可能使用的风格。

  • 声明变量但没有初始化时,请使用 var 当声明变量稍后将在函数中初始化时,请使用 var 关键字。```golangvar players int // 0

var things []Thing // an empty slice of Things

var thing Thing // empty Thing structjson.Unmarshall(reader, &thing)

  1. `var` 表示此变量已被声明为指定类型的零值。 这也与使用 `var` 而不是短声明语法在包级别声明变量的要求一致 - 尽管我稍后会说你根本不应该使用包级变量。
  2. * **在声明和初始化时,使用 `:=`。** 在同时声明和初始化变量时,也就是说我们不会将变量初始化为零值,我建议使用短变量声明。 这使得读者清楚地知道 `:=` 左侧的变量是初始化过的。
  3. 为了解释原因,让我们看看前面的例子,但这次是初始化每个变量:
  4. ```golang
  5. var players int = 0
  6. var things []Thing = nil
  7. var thing *Thing = new(Thing)
  8. json.Unmarshall(reader, thing)

在第一个和第三个例子中,因为在 Go 语言中没有从一种类型到另一种类型的自动转换; 赋值运算符左侧的类型必须与右侧的类型相同。 编译器可以从右侧的类型推断出声明的变量的类型,上面的例子可以更简洁地写为:

  1. var players = 0
  2. var things []Thing = nil
  3. var thing = new(Thing)
  4. json.Unmarshall(reader, thing)

我们将 players 初始化为 0,但这是多余的,因为 0players 的零值。 因此,要明确地表示使用零值, 我们将上面例子改写为:

  1. var players int

第二个声明如何? 我们不能省略类型而写作:

  1. var things = nil

因为 nil 没有类型。 [2]相反,我们有一个选择,如果我们要使用切片的零值则写作:

  1. var things []Thing

或者我们要创建一个有零元素的切片则写作:

  1. var things = make([]Thing, 0)

如果我们想要后者那么这不是切片的零值,所以我们应该向读者说明我们通过使用简短的声明形式做出这个选择:

  1. things := make([]Thing, 0)

这告诉读者我们已选择明确初始化事物。

下面是第三个声明,

  1. var thing = new(Thing)

既是初始化了变量又引入了一些 Go 程序员不喜欢的 new 关键字的罕见用法。 如果我们用推荐地简短声明语法,那么就变成了:

  1. thing := new(Thing)

这清楚地表明 thing 被初始化为 new(Thing) 的结果 - 一个指向 Thing 的指针 - 但依旧我们使用了 new 地罕见用法。 我们可以通过使用紧凑的文字结构初始化形式来解决这个问题,

  1. thing := &Thing{}

new(Thing) 相同,这就是为什么一些 Go 程序员对重复感到不满。 然而,这意味着我们使用指向 Thing{} 的指针初始化了 thing,也就是 Thing 的零值。

相反,我们应该认识到 thing 被声明为零值,并使用地址运算符将 thing 的地址传递给 json.Unmarshall

  1. var thing Thing
  2. json.Unmarshall(reader, &thing)

贴士:当然,任何经验法则,都有例外。 例如,有时两个变量密切相关,这样写会很奇怪:

  1. var min int
  2. max := 1000

如果这样声明可能更具可读性

  1. min, max := 0, 1000

综上所述:

在没有初始化的情况下声明变量时,请使用 var 语法。

声明并初始化变量时,请使用 :=

贴士:使复杂的声明显而易见。当事情变得复杂时,它看起来就会很复杂。例如

  1. var length uint32 = 0x80

这里 length 可能要与特定数字类型的库一起使用,并且 length 明确选择为 uint32 类型而不是短声明形式:

  1. length := uint32(0x80)

在第一个例子中,我故意违反了规则, 使用 var 声明带有初始化变量的。 这个决定与我的常用的形式不同,这给读者一个线索,告诉他们一些不寻常的事情将会发生。