8

100 Go mistakes之意外的变量隐藏

 2 years ago
source link: https://segmentfault.com/a/1190000040371148
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

100 Go mistakes之意外的变量隐藏

本文是对 《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.Client
if 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.Client
var 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错误。然而,一般来说,我们应该保持谨慎,因为我们已经看到我们可能会面临这样一种错误:代码可以编译,但可能不会对我们期望的变量进行赋值。在本章后面,我们将看到该如何检测变量隐藏,以帮助我们发现可能的错误。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK