Go 1.18版本正式发布了

本文永久链接 – https://tonybai.com/2022/03/16/go-1-18-released

美国时间2022年3月15日,Go核心团队官宣了Go 1.18版本正式版的发布!这是一个万众期待的版本,因为在这个版本中,Go核心团队做了Go语言开源以来的最大一次语法特性变更 – 增加了对泛型(generics)的支持!下面是对Go官博文章的全文翻译,供大家参考!


今天,Go团队很高兴地发布了Go 1.18,你可以通过访问下载页面获得该版本。

Go 1.18是一个真正的大版本,包括新功能特性、性能改进和我们对语言的最大改变。可以说Go 1.18的部分设计始于十年前我们首次发布Go语言的那个时候也并不夸张。

泛型(Generics)

在Go 1.18版本中,我们引入了对使用参数化类型的泛型代码的新支持。支持泛型是Go最常被要求添加的功能特性,我们很自豪能够提供大多数用户目前需要的泛型支持。随后的版本将继续为一些更复杂的泛型用例提供额外支持。我们鼓励你使用我们的泛型教程来了解这个新功能,并探索使用泛型来优化和简化你的代码的最佳方法。Go 1.18版本发布说明中有关于在Go 1.18中使用泛型的更多细节。

模糊测试(Fuzzing)

伴随着Go 1.18版本的发布,Go成为第一个将模糊测试(Fuzzing)完全集成到其标准工具链中的主要语言。与泛型一样,模糊测试的设计已经持续存在了很长时间,我们很高兴能在这个版本中与Go生态系统分享它。请查看我们的模糊测试教程,以帮助你开始使用这个新功能。

工作区(Workspaces)

今天,Go module几乎已被普遍接纳和采用,Go用户在我们的年度调查中报告了非常高的满意度分数。在我们2021年的用户调查中,用户反馈go module的最常见的挑战是跨多个module工作。在Go 1.18中,我们通过新的Go工作区模式(Go workspace mode)解决了这一问题,这使得在多个module中工作变得简单

20%的性能改进

苹果M1、ARM64和PowerPC64用户肯定会欢欣鼓舞! 由于Go 1.17的寄存器ABI调用约定扩展到这些架构,Go 1.18的CPU性能提升幅度高达20%。为了强调这个版本的性能提升幅度,我们将20%的性能改进作为了第四个最重要的标题

关于1.18中的所有内容的更详细描述,请查阅Go 1.18发布说明

Go 1.18是整个Go社区的一个巨大的里程碑。我们要感谢每一位提交错误、发送修改、编写教程或以任何方式帮助Go 1.18成为现实的Go用户。没有你们,我们无法做到这一点。谢谢你们。

享受Go 1.18吧!


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2022年,Gopher部落全面改版,将持续分享Go语言与Go应用领域的知识、技巧与实践,并增加诸多互动形式。欢迎大家加入!

img{512x368}

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

Go语言map类型变量背后的那些事儿

本文永久链接 – https://tonybai.com/2022/03/15/the-underlying-of-a-map-type-variable

切片(slice)和map是Go语言中最常用的两种原生复合数据类型,同时也是最容易使初学者感觉迷惑和“掉坑”的两个类型,这很大程度是因为Go runtime层的存在。什么是Go runtime层?可以参考我在《Go语言第一课FAQ》中的解释。

我们在Go用户源码层看到的切片与map是这样的:

var sl = make([]int, 3)
var m = make(map[string]int)

但在runtime层,它们又是另一幅“样子”。Go用户源码层的切片和map类型的变量,我常将它们称为“描述符”,因为它们和linux平台上通过open系统调用打开的文件描述符的功用十分类似,都是某个大块头儿数据(比如:一个500M的文本数据)的“代言人”,避免了和外界交互时对底层数据的搬动与拷贝。

很多人知道,在runtime层,切片是一个三元组结构(在我的“Go语言第一课”专栏中有单独一讲详细讲解),这里假定这个三元组结构为T,那么上面例子中通过make创建的切片m是类型T的实例还是*T的实例呢?很多人都知道答案:类型T的实例

同样看过我的专栏《Go语言精进之路》一书的读者也都知道:map类型在runtime层的表示为runtime.hmap,那么,上面通过make创建的map[string]int类型变量m究竟就是hmap类型实例还是*hmap类型实例呢?可能有些朋友还不明确,这里我们就来简单探究一下。

注:探究方法同样适用于切片类型。

m是hmap类型实例还是*hmap类型实例呢?最直接的方法是看runtime包的源码。在runtime/map.go中,我们找到了对应make(map[string]int)的源码makemap(或makemap_small):

func makemap(t *maptype, hint int, h *hmap) *hmap
func makemap_small() *hmap

我们看到:无论哪个函数返回的都是*hmap类型。到这里你的心里似乎有点倾向了,应该是*hmap。但还不那么确认。

我们假设m是*hmap,那么根据Go指针类型的定义(关于Go指针,我在专栏《聊聊Go语言中的指针》一讲中有较为全面讲解),Go为变量m分配的内存块中存储的值就应该是一个hmap实例的地址:

也就是说给m分配一块可以存储指针值的内存块儿即可。这样我们就可以通过相邻变量间的地址间隔来判定m是否仅仅是一个指针大小的内存块了。我们看下面例子:

package main

func main() {
    var a int = 5
    println("&a=", &a)
    var m1 = make(map[string]int)
    println("&m1=", &m1)
    var m2 = make(map[string]int)
    println("&m2=", &m2)
}

运行这个程序,输出结果如下:

&a=  0xc000046558
&m1= 0xc000046568
&m2= 0xc000046560

由于这些变量都分配在栈上(通过go build -gcflags ‘-m’可判断是否逃逸),我们用一幅图来展示一下上面示例中各个变量的内存块排列情况:

从m1与m2两个map类型变量的地址间隔情况来看,间隔8个字节,也就是一个指针大小,基本可以断定m2是指针类型实例了。

那么m是否是*hmap类型实例呢?如果是,我们是否可以通过对m的“解引用”得到该实例的值呢?我们下面试一下。

由于hmap是runtime包的非导出类型,所以我们无法在用户层直接使用,考虑到hmap都是由一些基本类型字段组成并且与runtime包的其他类型关联不多,我这里直接将其相关源码copy到示例源码中备用了。

package main

import (
    "fmt"
    "runtime"
    "unsafe"
)

type hmap struct {
    count     int // # live cells == size of map.  Must be first (used by len() builtin)
    flags     uint8
    B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
    noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
    hash0     uint32 // hash seed

    buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
    oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
    nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

    extra *mapextra // optional fields
}

// mapextra holds fields that are not present on all maps.
type mapextra struct {
    overflow    *[]*bmap
    oldoverflow *[]*bmap

    nextOverflow *bmap
}

// A bucket for a Go map.
type bmap struct {
    tophash [bucketCnt]uint8
}

const (
    // Maximum number of key/elem pairs a bucket can hold.
    bucketCntBits = 3
    bucketCnt     = 1 << bucketCntBits
)

func main() {
    m := make(map[string]int)
    m["tony"] = 11
    m["bai"] = 12
    p := (*hmap)(unsafe.Pointer(*(*uintptr)((unsafe.Pointer)(&m))))
    fmt.Printf("%#v\n", *p)
}

这个例子中最难理解的就是变量p的声明与赋初值那一行,对于这一行我们分解来讲一下。

首先,前面我们说过:map类型变量m是指针,其存储的是一个hmap类型实例的地址。通过

*(*uintptr)((unsafe.Pointer)(&m))

我们得到的是m指向的那个hmap类型实例的地址。

然后通过将其转换为*hmap类型,我们就相当于直接得到了一个指向hmap类型实例地址的*hmap类型变量p。通过对p进行解引用,我们就能看到hmap结构体的内容了。运行上面代码我们得到下面输出结果:

main.hmap{count:2, flags:0x0, B:0x0, noverflow:0x0, hash0:0x42833520, buckets:(unsafe.Pointer)(0xc000072ea0), oldbuckets:(unsafe.Pointer)(nil), nevacuate:0x0, extra:(*main.mapextra)(nil)}

当我们看到输出结果中hmap.count这个字段(表示当前map中存储的键值对的个数)的值为2,我们就可以确定:m就是一个执行hmap结构体实例的指针这一结论是正确的。


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2022年,Gopher部落全面改版,将持续分享Go语言与Go应用领域的知识、技巧与实践,并增加诸多互动形式。欢迎大家加入!

img{512x368}

img{512x368}
img{512x368}
img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats