本文是对 《100 Go Mistackes:How to Avoid Them》 一书的翻译。因翻译程度无限,不免存在翻译准确性问题,敬请体谅
变量的作用域是指它的可见性。换句话说,程序中的名称在哪局部是无效的。在Go中,在块中申明的变量名称能够在外部块中从新申明。这种被称为变量暗藏的准则很容易呈现谬误。
在上面的例子中,咱们将看到一个对于变量暗藏产生的bug。咱们将应用两种不同的形式创立一个HTTP客户端,具体取决于tracing布尔值:
var client *http.Client ①if tracing { client, err := createClientWithTracing() ② if err != nil { return err } log.Println(client)}else { client, err := createDefaultClient() ③ if err != nil { return err } log.Println(client)}//use client
① 生命一个client变量
② 应用带tracing的创立一个HTTP客户端,client变量在该块内被暗藏了
③ 创立一个默认的HTTP客户端,client变量在该模块仍然被暗藏掉了。
首先,咱们申明了一个client变量。而后,在两个外部块中,咱们应用 := 操作符,也叫做短变量申明运算符。该操作符应用和开始的时候雷同的名称创立了一个新的client变量;它不会为第①行中的client变量赋值。因而,在该示例中,HTTP客户端将始终是nil值。
留神:该代码之所以能够编译胜利,是因为在logging调用中应用了外部变量client。否则,咱们就会有编译谬误:client declared and not used。
咱们如何确保给client赋值了呢?有两种不同的办法。
第一种办法是在外部块中应用长期变量,像上面这样:
var client *http.Clientif tracing { c, err := createClientWithTracing() ① if err != nil { return err } client = c ②} else { c, err := createDefaultClient() if err != nil { return err } client = c}// Use client
① 创立了一个长期变量c
② 将长期变量赋给变量client
变量c的生命周期只在if/else块中。而后,咱们将这些变量赋值给client。
第二种形式是在外部块中应用赋值操作符(=)来将函数的返回值间接赋值给client变量。然而,它须要创立一个error变量,因为赋值运算符仅在已申明变量时才起作用。
var client *http.Clientvar err error ①if tracing { client, err = createClientWithTracing() ② if err != nil { return err }} else { client, err = createDefaultClient() if err != nil { return err }}
① 申明变量err
② 应用赋值操作符将返回来的*http.Client间接赋值给client变量
在这个例子中,咱们也将外部调用的后果赋值给了client。哪种办法最好呢?第一种办法在大多数状况下都是更不便的,然而没有强制说要是用哪种办法。
当在外部块中将一个变量名从新申明时就会产生变量暗藏,咱们曾经看到这种做法很容易出错。应依据我的项目和上下文制订防止暗藏变量的规定。例如,有时候,重用现有的变量名可能会很不便,像err谬误。然而,一般来说,咱们应该放弃审慎,因为咱们曾经看到咱们可能会面临这样一种谬误:代码能够编译,但可能不会对咱们冀望的变量进行赋值。在本章前面,咱们将看到该如何检测变量暗藏,以帮忙咱们发现可能的谬误。