前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >go1.16来啦

go1.16来啦

作者头像
用户3904122
发布2022-06-29 14:51:31
8140
发布2022-06-29 14:51:31
举报
文章被收录于专栏:光华路程序猿

翻译自 https://blog.logrocket.com/whats-new-in-go-1-16/ 发本文时距go1.16 release已经快两周了,今天也得空来翻一翻 学习下。

最新的Go版本1.16版在Go 1.15之后六个月到货。它的大部分更改是在工具链,运行时和库的实现中进行的。与往常一样,该版本保留了Go 1兼容性的承诺。作为Go编程语言的第17个主要版本Go 1.16。这是一项重大升级,为语言带来了许多期待已久的功能和改进。默认情况下,启用模块感知模式,Apple silicon支持实时可用,静态资源可以嵌入到二进制文件中,并且io / ioutil软件包中的方法已重新组织,因此现在具有逻辑意义。在本文中,我们将介绍此版本中的一些重点内容。

对Apple silicon的原生支持

自成立以来,Go一直优先考虑在不同操作系统和体系结构之间的可移植性,这体现在Go对各种操作系统和体系结构组合的支持上。具体可以参见(https://golang.org/doc/install/source#environment)

在过去的几个月中,由于Apple在CPU,GPU和电池性能方面的惊人飞跃,其首款64位ARM Mac的发布一直是开发人员中最主要的话题之一。Go项目迅速做出反应,通过添加GOOS = darwin和GOARCH = arm64环境变量对ARM Mac的本机进行支持。

如果你拥有M1 Mac,则现在可以在计算机上本地构建和运行Go程序;如果你使用的是其他操作系统或基于Intel的Mac,需要针对ARM Mac为你的程序构建二进制文件时,可以使用下面命令:

代码语言:javascript
复制
GOARCH=arm64 GOOS=darwin go build myapp

静态资源文件嵌入二进制文件

关于使用Go最好的事情之一就是可以将已编译程序作为单个不需要依赖的二进制文件进行分发和执行。当程序依赖于静态文件,比如HTML模板,数据库迁移文件,Web程序资源(例如JavaScript或图像文件等文件)时,通常必须将它们与二进制文件一起分发,除非将它们嵌入到二进制文件中,否则这种优势会有所抵消。

之前我们或许通过第三方软件包(例如pkger或packr)的帮助可以完成这项任务。但随着Go 1.16的发布,现在可以通过新的embed包原生得将静态文件本地包含在Go二进制文件中。

这里我们举个栗子来演示一下这个功能。假设您有一个sample.txt文件,其内容如下所示:

代码语言:javascript
复制
Hello from text file

并在同一目录中的main.go文件包含以下内容:

代码语言:javascript
复制
package main

import (
    _ "embed"
    "fmt"
)

//go:embed sample.txt
var text string

func main() {
    fmt.Print(text)
}

放在变量text上方的go:embed指令指示编译器将sample.txt文件的内容作为字符串嵌入到text变量中。如果使用go build生成程序并将生成的二进制文件移动到其他位置,则会注意到执行该程序仍然会将嵌入式文件的内容打印到标准输出中。这是因为sample.txt文件的所有内容都已包含在二进制文件中,因此可以按原样分发:

代码语言:javascript
复制
$ mv main /tmp
$ cd /tmp
$ ./main
Hello from text file

举一个更现实的例子,假设我们有一个具有以下目录结构的Web应用程序项目:

代码语言:javascript
复制
.
├── assets
│   ├── css
│   │   └── style.css
│   └── js
│       └── script.js
├── go.mod
├── index.html
├── main.go
└── random

我们可以将assets文件夹中所有文件和index.html文件嵌入二进制文件,如下所示

代码语言:javascript
复制
package main

import (
    "embed"
    "net/http"
)

//go:embed assets/*
var assets embed.FS

//go:embed index.html
var html []byte

func main() {
    fs := http.FileServer(http.FS(assets))
    http.Handle("/assets/", fs)
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Add("Content-Type", "text/html")
        w.Write(html)
    })
    http.ListenAndServe(":8080", nil)
}

像上面的示例一样,FS类型对于嵌入文件树(例如Web服务的资源文件)很有用。对于嵌入单个文件(如index.html),最好使用字符串或[] byte类型的变量。如果您构建并执行该程序,并导航至http:// localhost:8080,则将看到正确的静态的HTML文件的内容:

代码语言:javascript
复制
$ go version
go version go1.16rc1 linux/amd64
$ go build -o main
$ mv main /tmp
$ cd /tmp && ./main

browser

需要注意的陷阱

你必须先导入embed包,然后才能使用// go:embed指令。否则你将得到一个错误:

代码语言:javascript
复制
$ go run main.go
# command-line-arguments
./main.go:8:3: //go:embed only allowed in Go files that import "embed"

如果你不直接使用嵌入的任何导出标识,请确保在导入语句前添加下划线:

代码语言:javascript
复制
import (
    _ "embed"
)

要注意的另一件事是//go:embed仅适用于程序包级变量。如果你尝试在函数中使用它,则代码将无法编译:

代码语言:javascript
复制
package main

import (
    _ "embed"
    "fmt"
)

func main() {
    //go:embed index.html
    var html string
    fmt.Println(html)
}

输出

代码语言:javascript
复制
$ go run main.go
# command-line-arguments
./main.go:9:4: go:embed cannot apply to var inside func

GO111MODULE默认开启

Go 1.11中Go模块的引入预示着将移除GOPATH语义用于依赖管理的转变。在该初始发行版和Go 1.12中,模块仍处于实验阶段,必须使用环境变量GO111MODULE = on激活。Go 1.13确保只要当前工作目录或父目录中存在go.mod文件,即使该目录位于GOPATH中,模块模式都会自动激活,而Go 1.14和1.15仍然如此。

随着Go 1.16的发布,GO111MODULE变量现在默认为on,这意味着默认情况下启用了模块模式,而不管当前目录中是否存在go.mod文件。如果要还原为以前的行为,请将GO111MODULE设置为auto

在其他相关更改中,默认情况下,go buildgo test将不再修改go.modgo.sum文件。相反,如果需要添加或更新模块要求或校验和,将会报告错误。然后,您可以使用go mod tidygo get来相应地调整需求。

go install命令现在也可以识别模块,这意味着它不会影响当前目录或任何父目录(如果有)中的go.mod文件。而且,现在可以将版本号作为后缀。例如:

代码语言:javascript
复制
$ go install github.com/example@v3.5.0

在Go 1.16中,不赞成使用go get生成和安装软件包,而建议使用go install。在将来的发行版中,go get将不再能够构建和安装软件包,但将在启用-d标志的情况下按当前方式运行,这意味着它将在不构建软件包的情况下调整当前模块的依赖性。-insecure或-i标志也已被弃用。

retract

从Go 1.16开始,go.mod文件中将提供新的收回指令。这使软件包作者可以将较旧的软件包版本标记为不安全或已损坏,或者将版本标记为无意中发布。使用方法如下:

代码语言:javascript
复制
module example

go 1.16

retract v1.1.1 // retract single version
retract [v1.1.1, v1.3.2] // closed interval, so anything between v1.1.1 and v1.3.2

io/ioutil被废弃

现在,Go 1.16中已弃用整个ioutil软件包,其功能已移至其他软件包。需要明确的是,利用此程序包的现有代码将继续起作用,但是建议你迁移到ioos程序包中的新定义。

使用ioutil进行代码迁移应该很简单。此包中的一种流行方法是ReadAll(),该方法通常用于将整个请求正文从HTTP请求读取到一个字节片。该方法已移至io包:

代码语言:javascript
复制
resp, err := http.Get(url)
if err != nil {
    return err
}

defer resp.Body.Close()

// old way: body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
    return err
}

导出的io/ioutil方法的新位置的完整列表如下所示:

  • ioutil.Discard => io.Discard
  • ioutil.NopCloser => io.NopCloser
  • ioutil.ReadAll => io.ReadAll
  • ioutil.ReadDir => os.ReadDir (返回os.DirEntry切片,而不是fs.FileInfo切片)
  • ioutil.ReadFile => os.ReadFile
  • ioutil.TempDir => os.MkdirTemp
  • ioutil.TempFile => os.CreateTemp
  • ioutil.WriteFile => os.WriteFile

io/fs包

添加了io/fstesting/testfs软件包,因此不排除对Go标准库的改进。这些新软件包使在测试中抽象文件系统变得更加容易,这使它们无论在哪个操作系统上运行都更易于重现。访问文件的速度也将大大提高,之后您无需清理临时文件。

Go 1.16之前,模拟文件系统的任务通常落在流行的afero软件包中,该软件包提供了实现真实或模拟文件系统必须满足的接口类型。它还提供了一些提供此接口的常用实现,例如afero.MemMapFs,这是一个内存支持的文件系统,可用于测试中的模拟。

afero的Fs接口在撰写本文时定义13种方法不同,io/fs包提供的FS接口非常简单:

代码语言:javascript
复制
type FS interface {
    Open(name string) (File, error)
}

实现此接口所需要做的只是一个Open方法,该方法可以在路径中打开文件,并返回一个实现fs.File接口的对象,如下所示:

代码语言:javascript
复制
type File interface {
    Stat() (FileInfo, error)
    Read([]byte) (int, error)
    Close() error
}

你会从上面的接口中注意到的一件事是缺少允许你修改文件的方法。那是因为io / fs软件包仅提供文件系统的只读接口,而Afero则在这方面更加完善。做出此决定的原因是,与涉及更多内容的写相比,读更容易抽象。

All this is to say I think the design decision of limiting this proposal to read-only operations is a good one. In fact it was the key insight (by @robpike) that unlocked years of being stuck and let us make any progress defining this interface at all.

需要注意的点

现在,当在测试或基准测试期间创建的goroutine,对test.Ttesting.BFatalFatalfFailNow方法进行的调用无效时,vet工具会发出警告。这是因为这些方法退出了goroutine,而不是testbenchmark函数:

代码语言:javascript
复制
package main

import "testing"

func TestFoo(t *testing.T) {
    go func() {
        if true {
            t.Fatal("Test failed") // exits the goroutine instead of TestFoo
        }
    }()
}

fatal

可以调用t.Error()方法替换上面的方法来发出测试失败的信号,并使用return语句来退出goroutine:

代码语言:javascript
复制
package main

import "testing"

func TestFoo(t *testing.T) {
    go func() {
        if true {
            t.Error("Test failed.")
            return
        }
    }()
}

除了上述更新之外,还对标准库软件包进行了一些较小的更新和修复。完整的更改列表可在发行说明中找到(https://tip.golang.org/doc/go1.16#minor_library_changes)。

总结

如果要浏览此版本中包含的错误修复和功能的完整列表,建议你查看GitHubGo 1.16里程碑中已解决的问题列表。

最后祝大家猿宵节快乐~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光华路程序猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对Apple silicon的原生支持
  • 静态资源文件嵌入二进制文件
    • 需要注意的陷阱
    • GO111MODULE默认开启
    • retract
    • io/ioutil被废弃
    • io/fs包
    • 需要注意的点
    • 总结
    相关产品与服务
    GPU 云服务器
    GPU 云服务器(Cloud GPU Service,GPU)是提供 GPU 算力的弹性计算服务,具有超强的并行计算能力,作为 IaaS 层的尖兵利器,服务于生成式AI,自动驾驶,深度学习训练、科学计算、图形图像处理、视频编解码等场景。腾讯云随时提供触手可得的算力,有效缓解您的计算压力,提升业务效率与竞争力。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档