- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Go 泛型的三个核心设计,你学会了吗?由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
大家好,我是煎鱼.
Go1.18 的泛型是闹得沸沸扬扬,虽然之前写过很多篇针对泛型的一些设计和思考。但因为泛型的提案之前一直还没定型,所以就没有写完整介绍.
如今已经基本成型,就由煎鱼带大家一起摸透 Go 泛型。本文内容主要涉及泛型的 3 大核心概念,非常值得大家深入了解.
如下:
类型参数,这个名词。不熟悉的小伙伴咋一看就懵逼了.
泛型代码是使用抽象的数据类型编写的,我们将其称之为类型参数。当程序运行通用代码时,类型参数就会被类型参数所取代。也就是类型参数是泛型的抽象数据类型.
简单的泛型例子:
代码有一个 Print 函数,它打印出一个片断的每个元素,其中片断的元素类型,这里称为 T,是未知的.
这里引出了一个要做泛型语法设计的点,那就是:T 的泛型类型参数,应该如何定义?
在现有的设计中,分为两个部分:
结合完整的例子如下:
在上述代码中,我们声明了一个函数 Print,其有一个类型参数 T,类型约束为 any,表示为任意的类型,作用与 interface{} 一样。他的入参变量 s 是类型 T 的切片.
函数声明完了,在函数调用时,我们需要指定类型参数的类型。如下:
在上述代码中,我们指定了传入的类型参数为 int,并传入了 []int{1, 2, 3} 作为参数.
其他类型,例如 float64
也是类似的声明方式,照着套就好了.
说完类型参数,我们再说说 “约束”。在所有的类型参数中都要指定类型约束,才能叫做完整的泛型.
以下分为两个部分来具体展开讲解:
为了确保调用方能够满足接受方的程序诉求,保证程序中所应用的函数、运算符等特性能够正常运行.
泛型的类型参数,类型约束,相辅相成.
问题点 。
我们看看 Go 官方所提供的例子:
该方法的实现目的是:任何类型的切片都能转换成对应的字符串切片。但程序逻辑里有一个问题,那就是他的入参 T 是 any 类型,是任意类型都可以传入.
其内部又调用了 String 方法,自然也就会报错,因为只像是 int、float64 等类型,就可能没有实现该方法.
你说要定义有效的类型约束,那像是上面的例子,在泛型中如何实现呢?
要求传入方要有内置方法,就得定义一个 interface 来约束他.
单个类型 。
例子如下:
在泛型方法中应用:
再将 Stringer 类型放到原有的 any 类型处,就可以实现程序所需的诉求了.
多个类型 。
如果是多个类型约束。例子如下:
与常规的入参、出参类型声明一样的规则.
完成了函数约束的定义后,剩下一个要啃的大骨头就是 “运算符” 的约束了.
问题点 。
我们看看 Go 官方的例子:
经过上面的函数例子,我们很快能意识到这个程序根本无法运行成功.
其入参是 any 类型,程序内部是按 slice 类型来获取值,且在内部又进行运算符比较,那如果真是 slice,内部就可能每个值类型都不一样.
如果一个是 slice,一个是 int 类型,又如何进行运算符的值对比?
近似元素 。
可能有的同学想到了重载运算符,但...想太多了,Go 语言没有支持的计划。为此做了一个新的设计,那就是允许限制类型参数的类型范围.
语法如下:
例子如下:
上述声明的类型集是 ~int,也就是所有类型为 int 的类型(如:int、int8、int16、int32、int64)都能够满足这个类型约束的条件.
包括底层类型是 int8 类型的,例如:
也就是在该匹配范围内的.
联合元素 。
如果希望进一步缩小限定类型,可以结合分隔符来使用,用法为:
就可以将类型集限定在 int8 和 int64 之中.
实现运算符约束 。
基于新的语法,结合新的概念联合和近似元素,可以把程序改造一下,实现在泛型中的运算符的匹配.
类型约束的声明,如下:
应用的程序如下:
确保了值均为基础数据类型后,程序就可以正常运行了.
程序员写代码,一定程度的偷懒是必然的.
在一定的场景下,可以通过类型推导来避免明确地写出一些或所有的类型参数,编译器会进行自动识别.
建议复杂函数和参数能明确是最好的,否则读代码的同学会比较麻烦,可读性和可维护性的保证也是工作中重要的一点.
函数例子。如下:
公共代码片段。如下:
明确指定两个类型参数。如下:
只指定第一个类型参数,变量 f 被推断出来。如下:
不指定任何类型参数,让两者都被推断出来。如下:
神奇的在于,类型推导不仅限与此,连约束都可以推导.
函数例子,如下:
基于此的推导案例,如下:
MySlice 是一个 int 的切片类型别名。变量 V1 的类型编译器推导后 []int 类型,并不是 MySlice.
原因在于编译器在比较两者的类型时,会将 MySlice 类型识别为 []int,也就是 int 类型.
要实现 “正确” 的推导,需要如下定义:
基于此的推导案例。如下:
只要定义显式类型参数,就可以获得正确的类型,变量 V2 的类型会是 MySlice.
那如果不声明约束呢?如下:
编译器通过函数参数进行推导,也可以明确变量 V3 类型是 MySlice.
今天我们在文章中给大家介绍了泛型的三个重要概念,分别是:
类型参数:泛型的抽象数据类型.
类型约束:确保调用方能够满足接受方的程序诉求.
类型推导:避免明确地写出一些或所有的类型参数.
在内容中也涉及到了联合元素、近似元素、函数约束、运算符约束等新概念。本质上都是基于三个大概念延伸出来的新解决方法,一环扣一环.
你学会 Go 泛型了吗,设计的如何,欢迎一起讨论:) 。
Type Parameters Proposal 。
Summary of Go Generics Discussions 。
Go语言泛型设计 。
原文链接:https://mp.weixin.qq.com/s/I7qysvddG4NDgtYIMMAE3g 。
最后此篇关于Go 泛型的三个核心设计,你学会了吗?的文章就讲到这里了,如果你想了解更多关于Go 泛型的三个核心设计,你学会了吗?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
可以用这种方式转换字符串吗?我们有相同的参数,Java 做出了正确的选择。如果值是整数 - 我们调用 parseInt(value),否则如果值是 double 型 - 我们调用 parseDoubl
如果这段代码中有一个愚蠢的错误,我提前道歉,但我似乎无法解决它。我的问题是这样的,我用GCC-8(通过home-brew安装在Mac上)编译,然后在终端中执行。当使用 int do 定义变量 s &
我用 a-videosphere 制作了一个 a-scene。我尝试使用按钮启用/禁用声音,但有些想法不起作用?这是我的代码: var gargamel = 0; function
我正在使用 ISAAC 实现来生成随机整数。我需要用这些整数创建一个高斯值。首先,我需要将它们从 0 更改为 1 的 double 值。我怎样才能在Java中做到这一点?这是到目前为止我将整数转换为
我将 0x0000 到 0x01c2 范围内的十六进制值从 BLE 获取到我的手机 a 作为字符串。为了将其绘制在图表中,我必须将其转换为 double,我已经尝试过 this method但遗憾的是
我有一个父类(super class) Animal和一个子类 Dog 。在第三节课中,我有一个 List它同时接受子类型和父类(super class)型对象。 public class foo{
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我正在尝试查询我的用户的距离。我可以用这段代码做到这一点 PFGeoPoint.geoPointForCurrentLocationInBackground { (geoPoint: PFGe
考虑示例:http://jsfiddle.net/KWLu7/16/ 我正在尝试将总体重要性值计算为每个选定选择重要性的总和乘以其父标准重要性: var watch = $scope.$watch("
这个问题在这里已经有了答案: Bounding generics with 'super' keyword (6 个答案) 关闭 2 年前。 我有一个列表装饰器,它应该允许从一个列表转换到另一个列表
为什么下面的代码没有选择最近父类(super class)型的隐式 val? class A class B extends A trait TC[-T] { def show(t: T): Stri
这是我想要做的 def merge[A, B, C](eithers: Either[A,B]*)(implicit ev1: A x, x => x)) 关于scala - 推断常见的父类(s
我正在尝试从具有 double 类型列的Cassandra表中获取 double 值。我已经使用CQL3语法创建了表: CREATE TABLE data_double ( datetime
是否应该在不需要显式类型定义的情况下编译以下 this ? def prepList[B >: A](prefix: PlayList[B]) : PlayList[B] = prefix.fol
我正在查看某人的代码,并且在创建结构时使用了 abstract type AbstractFoo end julia> struct Foo1 struct Foo2 foo_op(x::Abst
一些示例代码: public class Main { class SomeType { } class A { protected T createSome
是否可以只接受类的泛型类型的父类(super class)型? 我正在寻找的是这样的: class MyClass { public void myMethod(TS someObject
在我的代码中,我有许多 ArrayList 被传递到排序方法中。每个 ArrayList 都有不同的泛型类型,但所有这些类型都是 Sorter 的实现。排序方法旨在接受 Sorter 类型的 Arra
如果已经有人问过这个问题,请链接并关闭这个问题。 我目前正在为另一个使用起来复杂得多(并且有潜在危险)的 API 的简化 API 设计原型(prototype)。 考虑到相关的有点复杂的对象创建,我决
我正在尝试构建一个具有某些依赖项的 android 应用程序,但是其中一个导致了此错误: Illegal class file: Class module-info is missing a supe
我是一名优秀的程序员,十分优秀!