go func()和 go_Go的泛型真的要来了—如何使用以及它们是怎么工作的


点击上方蓝色“Go语言中文网”关注我们,领全套Go资料,每天学习 Go 语言

你没看错,这里讲的就是 Go 中的泛型。只不过还没有正式发布,是基于草案设计的,已经是实现了可运行的版本。所以,泛型到来真的不远了!

Go 中的泛型已经接近成为现实。本文讲述的是泛型的最新设计,以及如何自己尝试泛型。

157698b0f802588418ba8ee00bcb8c34.png

Generics in Go —— How They Work and How to Play With Them

Go 由于不支持泛型而臭名昭著,但最近,泛型已接近成为现实。Go 团队实施了一个看起来比较稳定的设计草案,并且正以源到源翻译器原型的形式获得关注。本文讲述的是泛型的最新设计,以及如何自己尝试泛型。

例子

FIFO Stack

假设你要创建一个先进先出堆栈。没有泛型,你可能会这样实现:

type Stack []interface{}func (s Stack) Peek() interface{} { return s[len(s)-1]}func (s *Stack) Pop() { *s = (*s)[:len(*s)-1]}func (s *Stack) Push(value interface{}) { *s = append(*s, value)}

但是,这里存在一个问题:每当你 Peek 项时,都必须使用类型断言将其从 interface{} 转换为你需要的类型。如果你的堆栈是 *MyObject 的堆栈,则意味着很多 s.Peek().(*MyObject)这样的代码。这不仅让人眼花缭乱,而且还可能引发错误。比如忘记 * 怎么办?或者如果您输入错误的类型怎么办?s.Push(MyObject{})` 可以顺利编译,而且你可能不会发现到自己的错误,直到它影响到你的整个服务为止。

通常,使用 interface{} 是相对危险的。使用更多受限制的类型总是更安全,因为可以在编译时而不是运行时发现问题。

泛型通过允许类型具有类型参数来解决此问题:

type Stack(type T) []Tfunc (s Stack(T)) Peek() T { return s[len(s)-1]}func (s *Stack(T)) Pop() { *s = (*s)[:len(*s)-1]}func (s *Stack(T)) Push(value T) { *s = append(*s, value)}

这会向 Stack 添加一个类型参数,从而完全不需要 interface{}。现在,当你使用 Peek() 时,返回的值已经是原始类型,并且没有机会返回错误的值类型。这种方式更安全,更容易使用。(译注:就是看起来更丑陋,^-^)

此外,泛型代码通常更易于编译器优化,从而获得更好的性能(以二进制大小为代价)。如果我们对上面的非泛型代码和泛型代码进行基准测试,我们可以看到区别:

type MyObject struct {    X int}var sink MyObjectfunc BenchmarkGo1(b *testing.B) { for i := 0; i 

结果:

BenchmarkGo1BenchmarkGo1-16     12837528         87.0 ns/op       48 B/op        2 allocs/opBenchmarkGo2BenchmarkGo2-16     28406479         41.9 ns/op       24 B/op        2 allocs/op

在这种情况下,我们分配更少的内存,同时泛型的速度是非泛型的两倍。

合约(Contracts)

上面的堆栈示例适用于任何类型。但是,在许多情况下,你需要编写仅适用于具有某些特征的类型的代码。例如,你可能希望堆栈要求类型实现 String() 函数。这就是 Contracts :

contract stringer(T) { T String() string}type Stack(type T stringer) []T// Now we can use the String method of T:func (s Stack(T)) String() string { ret := "" for _, v := range s {  if ret != "" {   ret += ", "  }  ret += v.String() } return ret}

更多示例

以上示例仅涵盖了泛型的基础知识。你还可以在函数中添加类型参数,并在合约(Contracts)中添加特定类型。

有关更多示例,你可以从两个地方获得:

设计草案

设计草案包含更详细的描述以及更多示例:

https://go.googlesource.com/proposal/+/4a54a00950b56dd0096482d0edae46969d7432a6/design/go2draft-contracts.md,如果访问不了,可以看我备份的:https://github.com/polaris1119/go_dynamic_docs/blob/master/go2draft-contracts.md。

实现原型的 CL

原型 CL 也有几个示例。查找以“ .go2”结尾的文件:

https://go-review.googlesource.com/c/go/+/187317

如何尝试泛型?

使用 WebAssembly Playground

到目前为止,尝试泛型的最快,最简单的方法是通过 WebAssembly Playground[1]。它使用 WASM 构建的源代码到源代码翻译器原型在你的浏览器中直接运行 Go 代码。但这存在一些限制(请参见 https://github.com/ccbrown/wasm-go-playground)。

编译 CL

上面引用的 CL[2] 包含一个源到源转换器的实现,该转换器可用于将泛型代码编译为可以由 Go 的当前版本编译的代码。它将泛型代码(“多态”代码)称为Go 2代码,将非多态代码称为 Go 1 代码,但是根据实现的细节,泛型可能会成为 Go 1 版本而不是 Go 2 版本的一部分。

它还添加了一个 “go2go” 命令,可用于从 CLI 转换代码。

你可以按照 Go 的从源代码安装 Go 指令来编译 CL。当你到达可选的 “Switch to the master branch” 步骤时,请 用 checkout CL 代替:

git fetch "https://go.googlesource.com/go" refs/changes/17/187317/14 && git checkout FETCH_HEAD

请注意,这将检出补丁集 14,这是撰写本文时的最新补丁集。转到 CL[3] 并找到“下载”按钮以获取最新补丁集的签出命令。

编译 CL 之后,可以使用 go/* 包编写用于使用泛型的自定义工具,或者可以仅使用 go2go 命令行工具:

go tool go2go translate mygenericcode.go2

原文链接:https://blog.tempus-ex.com/generics-in-go-how-they-work-and-how-to-play-with-them/

作者:Chris Brown[4]

日期:2020-04-08

翻译:polaris

参考资料

[1]WebAssembly Playground: https://ccbrown.github.io/wasm-go-playground/experimental/generics/

[2]CL: https://go-review.googlesource.com/c/go/+/187317

[3]CL: https://go-review.googlesource.com/c/go/+/187317

[4]Chris Brown: https://blog.tempus-ex.com/author/chris/

推荐阅读

  • 你期待泛型吗?为什么Go语言没有泛型?何时会有?
  • Go和Rust的优缺点;预测Go1.16-1.19会支持泛型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575095.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bios设置_bios怎么设置显存 bios设置显存教程【图文】

有些用户可能会发现打开电脑系统信息窗口显示的内存容量与实际容量不同,例如系统内存显示4G,可用3.73G。那么不可用的那部分内存到哪里去了呢?其实是被集成显卡占用当做显存使用了。下面我们就通过 bios设置显存 来调整占用内存容量的大小,我…

4变形物体_Houdini基础(二)曲线变形物体

设想:先从二维上来看直角坐标系。物体是由x,y两个轴向的数据组成的。少了其中一组数据物体就只能是分布在单一轴向上的点。单独保留物体x、y情况下的点分布情况现在将x、y加起来,可见在三维空间中形成了一个平面。仅有x、y坐标的物体从目前的…

node.js+mysql实现分库分表存查数据:

node.jsmysql实现分库分表: 1.分库分表使用场景: 互联网项目中常用到的关系型数据库,如MySQL,随着用户和业务的增长,传统的单库单表模式难以满足大量的业务数据存储以及查询,单库单表中大量的数据会使写入…

Linux 添加新硬盘

1.识别分区和硬盘 在 /dev/ 目录下找到新的硬盘,sda 为本地硬盘,sda1、sda2.. 为分区,sdb 就是新添加的硬盘,如: [rootwusuyuan ~]# ls -ltr /dev/sd*brw-rw----. 1 root disk 8, 0 11月 14 14:12 /dev/sdabrw-rw----. 1 root di…

mybatis 映射成多个list_SSM:Mybatis架构与原理

MyBatis功能架构设计功能架构讲解:我们把Mybatis的功能架构分为三层:API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。数据处理层&…

10无法勾选隐藏的项目_Excel超好用的隐藏操作,不可多得

日常工作中,表格数据的展示与隐藏也是有大学问的,为了表格更加简洁明了、美观大气,实用的隐藏技巧就派上用场了。且听小翼慢慢分享~1、隐藏行列方法1:选中目标区域,右击鼠标选择“隐藏”即可。如图:方法2&a…

python程序题斐波那契数列_Python编程题9--斐波那契数列

题目1 已知一个数列:1、1、2、3、5、8、13、……,其规律为从第3项开始,每一项都等于其前两项的和,这个数列就是斐波那契数列。 请求出符合斐波那契数列规律的第11项。 代码实现--非递归 def fib_show(n): a, b 0, 1 while n >…

cocos2d-x,求世界坐标

老版: http://user.qzone.qq.com/350479720/blog/1384483239 一,求node的世界坐标。因为node的contentSize为0,局部坐标原点与node重合。所以求起来简单。下面方法都对:1,node->getParent()->convertToWorldSpace(node->…

pdf会签_跟我们做流程管理.pdf

跟我们做流程管理跟我们做流程管理——向管理要效益讲师简介陈立云 先生• AMT 高级咨询经理& 专家讲师• 暨南大学管理学院MBA教育中心校外导师• 著有畅销书 《跟我们做流程管理》,得到用户广泛好评• 曾先后在华为技术、美的电器、佳杰科技担任流程管理专家/…

python爬虫知乎图片_python爬虫(爬取知乎答案图片)

python爬虫(爬取知乎答案图片) 1.⾸先,你要在电脑⾥安装 python 的环境 我会提供2.7和3.6两个版本的代码,但是本⽂只以python3.6版本为例。 安装完成后,打开你电脑的终端(Terminal)执⾏以下命令&#xff1a…

HTML5简略介绍

今天要说下 HTML5特有的一个元素 canvas ,旨在让web页面上作矢量图不需要在依靠flash或是其他插件,在网页上使用canvas元素时,它会创建一块矩形区域,默认300*150,当然也是可以自定义的。Canvas中的坐标是从左上角开始的…

我的世界java和基岩版哪个好玩_我的世界:Java版本好玩还是基岩版好玩?老玩家看完后沉默了...

MC刚开始是在国外风靡了起来,传到中国的时候MC已经火了很久了,这时候外国已经出现了很多玩MC十分厉害的大神和主播,而在国外也有超多的服务器,其中有号称最强的原版生存服务器Scicraft,而在版本方面MC其实算下来大概有…

SQL Server简介

SQL Server是微软的一款关系型数据库。某些平台吹得天花烂坠,今天第一次在自己的项目中使用了下,感觉不是那么好,特别是SQL语句的支持度还是很欠缺,如limit等都不支持,还有特别单双引号都是需要特别注意的,下面是SQL S…

Windows下断言的类型及实现

一、内容综述 本文主要介绍Windows下断言assert的实现,并总结断言的不同应用准则。最后给出一个windows自定义断言的方法。 本文行文参考《Debugging Windows Programs》第三章相关内容,如果有兴趣的话建议读者可以深入阅读下。 二、断言的类型 1. ANSI…

mysql最大执行时间_导入大型MySQL数据库时,最大执行时间超过300秒

我正在尝试使用命令导入641 MBMySQL数据库&#xff1a;mysql -u root -p ddamiane_fakty < domenyin_damian_fakty.sql但是我收到了一个错误&#xff1a;ERROR 1064 (42000) at line 2351406: You have an error in your SQL syntax; check the manual that corresponds to …

linux右上角不显示网络连接_来体验下Linux吧

在前面的几期中我们从树莓派开始了解Linux&#xff0c;大家可能已经想来试一下手了。趁热打铁&#xff0c;本期我将介绍两种方便体验学习Linux的方法&#xff0c;在线体验或者安装虚拟机。1 在线体验Linux如果想快速的体验下Linux系统&#xff0c;我们可以选择云计算服务商提供…

debian下ror新建项目报错解决

一个是缺少mysql的开发包 sudo apt-get install libmysqld-dev 还有一个报错如下 debian ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. 要么自己下载nodejs的包,要么在gem…

mysql中的默认约束_数据库中默认约束的作用

匿名用户1级2016-04-29 回答数据库约束是为了保证数据的完整性而实现的一套机制&#xff0c;它具体的根据各个不同的数据库的实现而有不同的工具。一般来说有以下几种实现方式&#xff1a;1、检查约束&#xff1a;通过在定义数据库表里&#xff0c;在字段级或者是在表级加入的检…

python md5解密_python 生成文件MD5码

pymd5.py的代码如下&#xff1a; #-*-coding:utf-8-*-Created on 2012-5-25 author: kanpiaoxueimport hashlib import os import sys def printUsage(): print (Usage: [python] pymd5.py ) def createMD5(filePath): if not os.path.isfile(filePath): printUsage() else: tm…

Java数据结构、list集合、ArrayList集合、LinkedList集合、Vector集合

数据结构&#xff1a; 数据存储的常用结构有&#xff1a;栈、队列、数组、链表、红黑树。 栈&#xff1a;stack,又称堆栈&#xff0c;它是运算受限的线性表&#xff0c;其限制是仅允许在标的一端进行插入和删除操作&#xff0c;不允许在其他任何位置进行添加、查找、删除等操…