《GO语言圣经》读书笔记(九):包

本节读书笔记对应原书第十章。

​ 我们通过将一组相关的特性放到同一个包中,便于理解和后期更新,每个包更新的同时保持和程序中其他包的相对对立性,每个包都可以被其他的不同项目使用。

​ 这么多的包,我们给他们定义不同的名字,用于区分和标识访问。

​ 每个包还通过控制包内名字的可见性和是否导出来实现封装的特性,限制包内变量的可见性(有点类似于Java的private),用户必须通过特定的函数访问和更新变量(类似于Java通过getter/setter访问私有变量),保证内部变量的安全性。

包声明和导入声明

​ 每个go语言源文件的开头都必须有包声明语句,包声明语句的主要目的就是确定当前包被其他包导入时默认的标识符(也称为包名)。每个包是由一个全局唯一的字符串所标识的导入路径定位。出现在import语句中的导入路径是字符串。

​ 我们来举一个小例子说明一下,什么是包声明语句,如何导入包。

package main

import(
	"fmt"
    "math/rand"
)
func main(){
    fmt.Println(rand.Int())
}

math/rand包下的每个源文件第一行都是package rand包声明语句,当我们导入了这个包之后,就可以使用rand.Int类似的方式访问包成员。我们通过import可以导入我们需要使用的包。

​ 默认包名是包导入路径名的最后一段,因此即使两个包的导入路径不同,它们的包名可能是相同的。那这样的情况怎么办呢?比如math/randcrypto/rand包,那么导入声明必须至少为一个同名包指定一个新的包名以避免冲突,也就是导入包的重命名。

import(
	"crypto/rand"
    mrand"math/rand"
)

​ 不要担心,导入包的重命名只会影响当前文件,其他的文件如果也导入了math/rand包,可以用导入包原本默认的名字或者重命名为另一个完全不同的名字。

​ 当然了,导入包的重命名不仅可以解决名字冲突,如果我们导入的包名很笨重,那么可以通过重命名起一个简短的名称。

包的匿名导入

​ 如果只是导入一个包而并不使用导入的包,将会导致一个编译错误unused import。首先,解决第一个可能存在的疑虑:为什么导入包却不使用,那导入有啥用?如果我们只想执行导入包的init初始化函数或者计算包级变量的初始化表达式,那么我们就需要导入包了,但实际上可能并不会调用其中的方法/函数或使用变量。

​ 哈哈,有点跑题了,第二个问题,那要如何解决编译报错的问题呢?只需要用下划线重命名导入的包即可,如下所示。

import _"image/png"

​ 像这样的方式,我们就称为包的匿名导入。虽然这里重点并不是介绍png的相关使用,但还是说一下,一些图片的编解码器会支持一定的格式,如果没有编解码器,那么就没有办法正确识别和解码某一格式的图像,而png格式的图像通过注册驱动,让解码器检测识别到自己,最后玩转编解码工作。这个注册驱动就是在每个格式包的init初始化函数中调用的。

​ 再举一个使用包的匿名导入的例子,比如数据库包database/sql,用户可能会使用不同的数据库驱动,那么就需要执行对应驱动的init函数,一般init函数会做一些注册工作。

import(
	"database/sql"
    _"github.com/lib/pq" //支持Postgres"github.com/go-sql-driver/mysql"//支持MySQL
)

db,err=sql.Open("postgres",dbname)
db,err=sql.Open("mysql",dbname)
db,err=sql.Open("sqlite3",dbname) //会返回错误,因为没有导入sqllite的驱动

题外话:为什么go语言的编译速度如此之快?

​ 这主要得益于三个语言特性。

  • 所有导入的包必须再每个文件的开头显式声明,这样的话编译器就没有必要读取和分析整个源文件来判断包的依赖关系;
  • 禁止包的环状依赖,每个包可以被独立编译,而且很可能是被并发编译;
  • 编译后包的目标文件不仅仅记录包本身的导出信息,目标文件同时还记录包的依赖关系

​ 所以,编译器只需要读取每个直接导入包的目标文件,而不需要遍历所有依赖的文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值