导包和声明
当包名重复时
如果我们想同时导入两个有着名字相同的包,例如math/rand包和crypto/rand包,那么导入声明必须至少为一个同名包指定一个新的包名以避免冲突。这叫做导入包的重命名。
import (
"crypto/rand"
mrand "math/rand" // alternative name mrand avoids conflict
)
导入包的重命名只影响当前的源文件。其它的源文件如果导入了相同的包,可以用导入包原本默认的名字或重命名为另一个完全不同的名字。
包的匿名导入
如果只是导入一个包而并不使用导入的包将会导致一个编译错误。但是有时候我们只是想利用导入包而产生的副作用:它会计算包级变量的初始化表达式和执行导入包的init初始化函数。这时候我们需要抑制“unused import”编译错误,我们可以用下划线_
来重命名导入的包。像往常一样,下划线_
为空白标识符,并不能被访问。
import _ "image/png" // register PNG decoder
这个被称为包的匿名导入。它通常是用来实现一个编译时机制,然后通过在main主程序入口选择性地导入附加的包。首先,让我们看看如何使用该特性,然后再看看它是如何工作的。
标准库的image图像包包含了一个Decode
函数,用于从io.Reader
接口读取数据并解码图像,它调用底层注册的图像解码器来完成任务,然后返回image.Image类型的图像。使用image.Decode
很容易编写一个图像格式的转换工具,读取一种格式的图像,然后编码为另一种图像格式:
package main
import (
"fmt"
"image"
"image/jpeg"
_ "image/png"
"io"
"os"
)
func main() {
if len(os.Args) < 3 {
fmt.Println("using ./ aaa.png bbb.jpg")
}
inFilename := os.Args[1]
outFilename := os.Args[2]
infile, err := os.Open(inFilename)
if err != nil {
fmt.Println(err)
return
}
defer infile.Close()
outfile, err := os.Create(outFilename)
if err != nil {
fmt.Println(err)
return
}
defer outfile.Close()
toJPEG(infile, outfile)
}
func toJPEG(in io.Reader, out io.Writer) error {
//将传递进来的文件解码
img, kind, err := image.Decode(in)
if err != nil {
return err
}
fmt.Fprintln(os.Stderr, "Input format = ", kind)
return jpeg.Encode(out, img, &jpeg.Options{Quality: 95})
}
因为jpeg会用到png格式,但是我们的代码并没有用到,所以如果不import image/png,编译没有问题,但是不会生成png图片,
要是import image/png则会被编译器告知,没有使用这个包而报错,所以就只有使用匿名的import方式。