proxy的好处自然不用多说,它可以使国内开发者畅通无阻地访问某些国内环境无法获取的包。更重要的是默认的proxy是官方提供和维护的,比起第三方方案来说安全性有了更大的保障。
GOSUMDB这个变量实际上相当于指定了一个由官方管理的在线的go.sum数据库。具体介绍之前我们先来看看golang是如何验证packages的:
go get下载的package会根据go.mod文件和所有下载文件分别建立一个hash字符串,存储在go.sum文件中;
下载的package会被cache,每次编译或者手动go mod verify时会重新计算与go.sum中的值比较,出现不一致就会报安全错误。
这个机制是建立在本地的cache在整个开发生命周期中不会变动之上的(因为依赖库的版本很少会进行更新,除非出现重大安全问题),上述机制可以避免他人误更新依赖或是本地的恶意篡改,然而现在更多的安全问题是发生在远程环境的,因此这一机制有很大的安全隐患。
好在加入了GOSUMDB,它的默认值为“sum.golang.org”,国内部分地区无法访问,可以改为“sum.golang.google.cn”。现在的工作机制是这样的:
go get下载包并计算校验和,计算好后会先检查是否已经出现在go.sum文件中,如果没有则去GOSUMDB中检查,校验和一致则写入go.sum文件;否则报错
如果对应版本的包的校验和已经在go.sum中,则不会请求GOSUMDB,其余步骤和旧机制一样。
安全性得到了增强。
GOPRIVATE最后要介绍的是GOPRIVATE,默认为空,你可以在其中使用类似Linux glob通配符的语法来指定某些或某一类包不从proxy下载,比如某些rpc套件自动生成的package,这些在proxy中并不会存在,而且即使上传上去也没有意义,因此你需要把它写入GOPRIVATE中。
还有一个与其类似的环境变量叫GONOPROXY,值的形式一样,作用也基本一样,不过它会覆盖GOPRIVATE。比如将其设为none时所有的包都会从proxy进行获取。
从这些变化来看go团队始终在寻找一种能细粒度控制的统一的包管理解决方案,虽然目前和npm、pypi还有巨大的差距,但仍不失为成功道路上的坚实一步。
标准库的新功能每次新版本发布都会给标准库带来大把的新功能新特性,这次也不例外。
本节会介绍一个小的新功能,以及一个重要的新变化。
判断变量是否为0值golang中任何类型的0值都有明确的定义,然而遗憾的是不同的类型0值不同,特别是那些自定义类型,如果你要判断一个变量是否0值那么将会写出复杂繁琐而且扩展困难的代码。
因此reflect中新增了这一功能简化了操作:
package main import ( "fmt" "reflect" ) func main() { a := 0 b := 1 c := "" d := "a" fmt.Println(reflect.ValueOf(a).IsZero()) // true fmt.Println(reflect.ValueOf(b).IsZero()) // false fmt.Println(reflect.ValueOf(c).IsZero()) // true fmt.Println(reflect.ValueOf(d).IsZero()) // false }当然,反射一劳永逸的代价是更高的性能消耗,所以具体取舍还要参照实际环境。
错误处理的革新其实算不上革新,只是对现有做法的小修小补。golang团队始终有觉得error既然是值那就一定得体现value的equal操作的怪癖,所以整体上还是很怪。
首先要介绍错误链(error chains)的概念。
在1.13中,我们可以给error实现一个Unwrap的方法,从而实现对error的包装,比如:
type PermError { os.SyscallError Pid uint Uid uint } func (err *PermError) String() string { return fmt.Sprintf("permission error:\npid:%v\nuid:\ninfo:%v", err.Pid, err.Uid, err.SyscallError) } func (err *PermError) Error() string { return err.String() } // 重点在这里 func (err *PermError) Unwrap() error { return err.SyscallError }假设我们包装了一个基于SyscallError的权限错误,包括了所有因为权限问题而触发的error。String和Error方法都是常规的自定义错误中会实现的方法,我们重点看Unwrap方法。
Unwrap字面意思就是去包装,也就是我们把包装好的上一层错误重新分离出来并返回。os.SyscallError也实现了Unwrap,于是你可以继续向上追溯直达最原始的没有实现Unwrap的那个error为止。我们称从PermError开始到最顶层的error为一条错误链。
如果我们用→指向Unwrap返回的对象,会形成下面的结构:
PermError → os.SyscallError → error
还可以出现更复杂的结构:
A → Err1 ___________
|
V
B → Err2 → Err3 → error