zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Go语言中常见100问题-#14 Ignoring package name collisions

2023-02-18 16:32:46 时间

忽视包名冲突

当变量名与包名相同时会发生包冲突,会阻止包被重用。下面来看一个Redis客户端库的具体例子。

package redis
 
type Client struct { ... }
 
func NewClient() *Client { ... }
 
func (c *Client) Get(key string) (string, error) { ... }

上述代码保存在redis库中,现在有一个客户端程序,使用到上面的redis包提供的功能。尽管调用的包名是redis,但在Go语言中创建一个名为redis的变量是完全有效的。

redis := redis.NewClient()
v, err := redis.Get("foo")

上面这个客户端调用程序中变量名和包名都是redis,虽然语法上没有任何问题,但是应该避免这种做法。这会导致在整个redis变量的作用域范围内,redis包将无法访问。

假设在一个函数中同时使用了变量redis和包名redis,在这种情况下,阅读代码的时候可能混淆不清。有哪些方法可以避免这种冲突呢?第一种处理方法是使用不同的变量名,例如像下面变量取名为redisClient。

redisClient := redis.NewClient()
v, err := redisClient.Get("foo")

虽然上面这种做法非常直接有效,但是,如果出现某种原因我们更喜欢保留名为redis的变量,这时可以在导入包上做点文章,给导入包起一个别名,代码中使用包的别名可以避免冲突,示例程序如下。使用redisapi导入别名来引用redis包,这样就可以保留变量名redis.

import redisapi "mylib/redis"
 
// ...
 
redis := redisapi.NewClient()
v, err := redis.Get("foo")

「NOTE:还有一种做法是导包时使用 . 导入来访问没有包限定符的包中的所有公共元素。然而,这种方法往往会增加混淆,在大多数情况下应该避免使用。」

还要注意,我们应该避免变量名和内置函数名之间的名称相同冲突。例如,下面这个拷贝操作, 函数 copyFile 返回结果赋值给了变量 copy, 与内置的函数 copy 冲突了,导致内置的copy函数无法访问。我们应该防止变量名冲突以避免歧义。如果遇到冲突,我们应该找到另一个有意义的名称或使用导入包别名。

copy := copyFile(src, dst)