Go 1.20要来了,看看都有哪些变化-第1篇

前言

Go官方团队在2022.12.08发布了Go 1.20 rc1(release candidate)版本,Go 1.20的正式release版本预计会在2023年2月份发布。

让我们先睹为快,看看Go 1.20给我们带来了哪些变化。(文末有彩蛋!)

安装方法:

$ go install golang.org/dl/go1.20rc1@latest
$ go1.20rc1 download

这是Go 1.20版本更新内容详解的第1篇,欢迎大家关注公众号,及时获取本系列最新更新。

Go 1.20发布清单

和Go 1.19相比,改动内容适中,主要涉及语言(Language)、可移植性(Ports)、工具链(Go Tools)、运行时(Runtime)、编译器(Compiler)、汇编器(Assembler)、链接器(Linker)和核心库(Core library)等方面的优化。

我们逐个看看具体都有哪些变化。

语言变化

Go 1.20在语言层面带来了4个变化。

slice转数组

Go1.17在语言层面开始支持将slice转为指向数组的指针。

示例如下:

s := make([]byte, 2, 4)
// 将s这个slice转为指向byte数组的指针s0
// 其中[0]byte里的0表示数组的长度,虽然长度为0,但值不等于nil
s0 := (*[0]byte)(s)      // s0 != nil
fmt.Printf("%T")
// 将s[1:]这个slice转为指向byte数组的指针s1
// s1指向的数组的长度为1
s1 := (*[1]byte)(s[1:])  // &s1[0] == &s[1]
// 将s这个slice转为指向byte数组的指针s2
// s2指向的数组的长度为2 
s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
// 将s这个slice转为指向byte数组的指针s4
// s4指向的数组的长度为4 
s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)

注意:slice转为指向数组的指针时,如果数组定义的长度超过了slice的长度,会抛panic。

所以上面s4 := (*[4]byte)(s)这行代码虽然可以编译通过,但是会出现runtime panic。

Go 1.20之前不支持将slice直接转为数组,如果要转,得先转为指向数组的指针,再转为数组,如下面代码所示:

s := make([]byte, 2, 4)
s[0] = 100

s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]
s2 := (*[2]byte)(s)     // &s2[0] == &s[0]
fmt.Printf("%T, %v, %p, %p\n", s1, s1[0], &s1[0], &s[1])
fmt.Printf("%T, %v, %v, %p\n", s2, s2[0], &s2[0], s)
// a1数组里元素的地址和s1指向的数组的元素地址不一样,a2同理
a1 := *s1
a2 := *s2
fmt.Printf("%T, %v, %p, %p\n", a1, a1[0], &a1[0], &s1[0])
fmt.Printf("%T, %v, %p, %p\n", a2, a2[0], &a2[1], &s2[1])

从Go 1.20开始,支持将slice直接转为数组,如下面代码所示:

s := make([]byte, 2, 4)
s[0] = 100
s1 := [1]byte(s[1:])
s2 := [2]byte(s)
// s1数组里元素的地址和s指向的数组的元素地址不一样,s2同理
fmt.Printf("%T, %v, %p, %p\n", s1, s1[0], &s1[0], &s[1])
fmt.Printf("%T, %v, %v, %p\n", s2, s2[0], &s2[0], s)

总结:

  • slice转为指向数组的指针后,这个指针会指向和slice相同的地址空间
  • slice转为数组时,会把slice底层数组的值拷贝一份出来。转换后得到的数组的地址空间和slice底层数组空间不一样。

还有几个语法细节可以参考如下代码示例:

var t []string
t0 := [0]string(t)       // ok for nil slice t
t1 := (*[0]string)(t)    // t1 == nil
t2 := (*[1]string)(t)    // panics: len([1]string) > len(t)

u := make([]byte, 0)
u0 := (*[0]byte)(u)      // u0 != nil

Comparable类型

Go泛型里comparable这个类型约束(type constraint)有个坑,就是和Go语言里定义的可比较类型(Comparable types)并不一致。

什么是comparable types,简单来说就是可以用==!=来进行比较的类型就是comparable types。

The equality operators == and != apply to operands that are comparable.

The ordering operators <, <=, >, and >= apply to operands that are ordered.

有些可比较类型的变量不能作为类型实参(type argument)赋值给声明了comparable类型约束的类型参数(type parameter)。

例如Go语言说明里有如下这段内容:

Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

这里明确指出,接口类型的值是可比较的,但是我们不能把2个interface作为类型实参给到类型参数。

参考如下代码示例:

// example4.g0
package main

import "fmt"

func IsEqual[T comparable](a T, b T "T comparable") bool {
    return a == b
}

func main() {
    var a interface{} = 1
    var b interface{} = []int{1}
    fmt.Println(a == b) // false
  // go1.20之前的版本编译报错,go1.20开始支持
    fmt.Println(IsEqual(a, b)) 
}

对于上面最后一行代码,Go 1.20之前的版本编译报错。

$ go1.18 run example4.go
./example4.go:13:21: interface{} does not implement comparable

因为Go 1.20之前的版本认为空接口类型interface{}并没有实现comparable类型约束,不能作为类型实参传给类型参数。

从Go 1.20版本开始,不会编译报错,因为interface类型是comparable type,程序执行结果如下:

$ go1.20rc1 run example4.go
false
false

具体哪些类型是comparable type可以参考:Comparable types 里的说明。

unsafe包

Go 1.17版本在unsafe package里引入了Slice函数,如下所示:

func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType

在Go 1.20版本里,标准库unsafe package定义了3个新的函数:

func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte

有了这4个函数,可以构造和解构slice和string。

具体细节可以参考:https://tip.golang.org/ref/sp...

值比较

Go语言说明现在明确指出结构体变量的值每次只比较一个字段,字段比较的顺序和字段在结构体里定义的顺序保持一致。

一旦某个字段的值比较出现不一致,就会马上停止比较。

以前的说明可能会让Go开发者有误解,以为结构体变量的比较需要比较所有字段,实际并不是。

类似的,数组的比较也是每次只比较一个元素,按照数组的下标索引由小到大逐个比较数组里每个元素的值。

这块只是改了说明而已,对大家的代码没有任何影响。

可移植性

Darwin and iOS

Go 1.20将会成为支持macOS 10.13 High Sierra和10.14 Mojave的最后一个版本。

如果未来想在mac电脑上使用Go 1.21或者更新的Go版本,只能用macOS 10.15 Catalina和更新的macOS版本。

FreeBSD/RISC-V

Go 1.20增加了对于RISC-V架构在FreeBSD操作系统的实验性支持。

GOOS=freebsd
GOARCH=riscv64

总结

下一篇会介绍Go 1.20在Go Tool工具链、运行时、编译器、汇编器、链接器和核心库的优化工作,有一些内容值得学习,欢迎大家保持关注。

开源地址

文章和示例代码开源在GitHub: Go语言初级、中级和高级教程

公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

个人网站:Jincheng's Blog

知乎:无忌

福利

我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。

关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。

最后送上一个彩蛋,Go标准库的脑图,想学习Go标准库的可以参考这个来。

References

0 条评论
请不要发布违法违规有害信息,如发现请及时举报或反馈
还没有人评论呢,速度抢占沙发!
相关文章
  • golang pprof监控系列(2) —— memory,block,mutex 使用 大家好,我是蓝胖子。 profile的中文被翻译轮廓,对于计算机程序而言,抛开业务逻辑不谈,它的轮廓是是啥...

  • 接口接口的定义这里用一个例子说明了golang中接口的含义与用法,先看代码 // Launch the goroutine to perform the search. ...

  • github: https://github.com/jinzhu/copier由于 golang 没有对复杂结构体的 clone 方法,所以,就需要有 copier 这样的工具库。它看起来很简单,但...

  • 前言Google官方在2022.11.23重磅发布了Go语言编码规范。这个编码规范源自于Google内部的Go项目,是Google的开发人员要遵守的代码规范。在Go语言诞生后,全世界的Go开发者其实一...

  • Antlr4 简介 ANTLR(全名:ANother Tool for Language Recognition)是基于LL(*)算法实现的语法解析器生成器(parser generator),用J...

  • 学习Go快两年了,一些资料进行整理。 Go语言基础书籍 Go语言圣经——《Go程序设计语言》机械工业出版社作 【推荐】 在线版:Go 语言设计与实现 | Go 语言设计与实现 (dravenes...

  • 1 实验问题描述 设计程序模拟先进先出FIFO,最佳置换OPT和最近最久未使用LRU页面置换算法的工作过程。假设内存中分配给每个进程的最小物理块数为m,在进程运行过程中要访问的页面个数为n,页面访问序...

  • 概述goroutine 是 Go 程序并发执行的实体,对于初学者来讲,可以简单地将 goroutine 理解为一个 超轻量的线程。当一个程序启动时,只有一个 goroutine 调用 main 函数,...

  • 1、Golang中死锁的触发条件 1.1 书上关于死锁的四个必要条件的讲解 发生死锁时,线程永远不能完成,系统资源被阻碍使用,以致于阻止了其他作业开始执行。在讨论处理死锁问题的各种方法之前,我们首先深...

  • 自增和主流编程语言的自增语法不同,Go 只支持 i++ 方式,不支持 ++i 方式。正确package main func main() { i := 1 i++ print...

  • Hello,Golang 一、开发环境搭建 1. 下载 SDK // Go官网下载地址 https://golang.org/dl/ // Go官方镜像站(推荐) https://go...

  • Part 1 背景Golang作为云原生领域中使用最广泛的编程技术,是我们MatrixOrigin数据库主力开发语言。Golang本身提供了pprof性能剖析工具,可以让我们快速,粗略的分析性能瓶颈,...

  • dongle 是一个轻量级、语义化、对开发者友好的 Golang 编码解码和加密解密库Dongle 已被 awesome-go 收录, 如果您觉得不错,请给个 star 吧github.com/gol...

  • 概述new() 函数为数据类型 T 分配一块内存,初始化为类型 T 的零值,返回类型为指向数据的指针,可以用于所有数据类型。make() 函数除了为数据类型 T 分配内存外,还可以指定长度和容量,返回...

  • 概述 Go 支持将多个结构体通过嵌套的方式,组成一个大的结构体,降低了单个结构体复杂度,同时提高了结构体之间组合的灵活性。 例子 为了省略篇幅,本小节只使用 字面量 方式初始化,new() 的初始化方...

  • 基础 语法 只记录需要特别注意的点 Diff 变量声明未使用会 CE。 _ 的妙用 交换变量:a, b = b, a 空白标识符 _ 用于抛弃值,如值 5 在:_, b = 5, 7 中被抛弃。 ...

  • 1. Kafka介绍 1.1.1. Kafka是什么 kafka使用scala开发,支持多语言客户端(c++、java、python、go等) Kafka最先由LinkedIn公司开发...

  • 1. 前言 所谓的逃逸分析(Escape analysis)是指由编译器决定内存分配的位置吗不需要程序员指定。 函数中申请一个新的对象 如果分配在栈中, 则函数执行结束后可自动将内存回收 如果分配...

  • 一 JWT介绍 JWT 英文名是 Json Web Token ,是一种用于通信双方之间传递安全信息的简洁的、URL安全的表述性声明规范,经常用在跨域身份验证。 JWT 以 JSON 对象的形式安全传...

  • 概述调用 sync/atomic 包即可。错误的并发操作先来看一个错误的示例。通过启动 1000 个 goroutine 来模拟并发调用,在函数内部对变量 number 进行自增操作,那么可能存在的一...