Go语言必知必会100问题-01 小心变量遮蔽

小心变量遮蔽

变量的作用域是指一个变量可以被引用的地方/范围。换句话说,就是应用程序的一个区域,在该区域内变量是有效的,超出该区域便无效。在Go语言中,在代码块中声明的变量可以在内部代码块中重新声明,这种使用方法称为变量遮蔽/隐藏,注意在使用时要非常小心,否则很容易出现常见的错误。下面通过一个具体的程序例子说明变量遮蔽/隐藏导致的问题,程序中将以两种不同的方式创建 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, 然后在两个内部代码块中使用短变量声明运算符(:=)赋值,虽然赋值给的变量也是client,但是它与外面的client不是同一个,因此,执行上述程序外部的client始终为nil.

NOTE: 上面的代码可以编译通过,因为内部赋值的client变量在log.Println中使用到了,否则的话,将出现编译错误,提示client(内部的)声明但未使用。

如何修复上面代码中存在的问题呢?有两种不同的方法。方法一是在内部代码块中使用一个临时变量保存client,此临时变量名不要使用client,然后再将临时变量值赋值给client, 实现代码如下。这里先将结果保存在临时变量c中,c的作用域在if块中,最后再将c赋值给客户端变量client.

var client *http.Client
if tracing {
        c, err := createClientWithTracing()
        if err != nil {
                return err
        }
        client = c
} else {
        // Same logic
}

方法二是使用赋值运算符(=)将创建结果直接分配给客户端变量client,但是需要创建一个错误变量,因为赋值运算符(=)对已声明的变量才能使用。然后直接将创建结果分配给client,实现如下。

var client *http.Client
var err error
if tracing {
        client, err = createClientWithTracing()
        if err != nil {
                return err
        }
} else {
        // Same logic
}

上述两种方法都是正确的,主要区别在于方法二种只执行了一个赋值操作,阅读起来可能更容易。此外,使用方法二,可以在if/else语句之后统一对错误进行处理。

if tracing {
        client, err = createClientWithTracing()
} else {
        client, err = createDefaultClient()
}
if err != nil {
        // Common error handling
}

总结,在内部代码块中重新声明变量时,会产生变量遮蔽/隐藏,通过前面的例子可以看到这种做法很容易出错。所以在编码中,注重代码品味,尽量不要犯变量遮蔽/隐藏问题。虽然有时重用现有变量会非常方便,例如在用err表示错误时。但是,总体来说,我们应该谨慎小心,否则很容易出现问题,像本文举的例子,接收到值的变量不是我们预期的变量。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值