Go 泛型函数中的 ~ 符号 的意义 -- 用于指定类型的底层类型

本文通过 slices.Clone 泛型函数介绍了 Go 是如何使用类型推断完成参数类型的解构。简单来说,如果第一个类型参数是一个复合类型,则可以通过第二、第三或更多的类型参数约束复杂类型中的类型参数,而类型推断则可以通过第一个参数推断出后续类型参数的实际类型。另外本文还说明为消除歧义而引入 ~ 符号,即用于指定类型的底层类型。

slices.Clone()函数原型

Go 复制代码
func Clone[S ~[]E, E any](s S) S {
    return append(s[:0:0], s...)
}

上面的 [S ~[]E, E any] 表示 S 可以是任意底层类型是 slice 的任意类型。

如果上面的类型约束中没有 ~ 符号,如 [S []E, E any] 表示类型参数 S 可以是一个 slice 类型,但不能是一个 slice 的命名类型。

如果 Go 语法中不使用 ~,那么 [S []E] 将会精确匹配到任意以 []E 作为底层类型的类型,这样我们就不得不定义 [S MySlice] 作为约束。

Go 语法禁止 [S MySlice],或者说 [S MySlice] 只能匹配到 MySlice,但是对语言预定义的类型会造成困惑。作为预定义类型的 int,其底层类型依然是 int。我们希望 Go 语言能够能开发者提供精确匹配和定义约束底层类型为 int 的方式,如在程序中使用 [T ~int]。如果我们不使用 ~,[T int] 不能很好表明要使用底层类型为 int 语义。如果这么做了,那么 [T MySlice] 和 [T int] 的约束行为就会有歧义。

我们可能会认为 [S MySlice] 匹配任意底层类型为 MySlice 的底层类型的类型,但这样会很困惑。

所以我们觉得使用 ~ 表明其底层类型会更好一些。

解构类型参数

我们使用到的技术,即定义一个使用类型参数 E 的类型参数 S,是一种在泛型函数签名中解构类型的方式。通过解构类型,我们可以命名、约束类型的各个方面。

比如,maps.Clone 的签名如下:

Go 复制代码
func Clone[M ~map[K]V, K comparable, V any](m M) M

和 slices.Clone 一样,我们使用了类型参数 M 来约束参数 m,然后定义类型参数 K 和 V 用于解构类型。

在 maps.Clone 中,我们约束 K 必须是可比较型的,这与 map 的 key 的约束一致。也正因为这一特性,我们可以在开发过程中实现对复合类型的解构。

Go 复制代码
func WithStrings[S ~[]E, E interface { String() string }](s S) (S, []string)

上述示例中,我们要求 WithStrings 的参数类型必须是一个元素类型为带 String 方法的 slice。

因此,我们可以 Go 语言中在复合类型中使用类型推断来推断出其实际类型。

~ 使用示例 [S ~[]E, E comparable] 约束 使用示例

Go 复制代码
package main

import (
	"fmt"
)

func main() {
	var s1 = []int{1, 2, 7, 8, 1, 12, 16, 18, 20, 99}
	ret := Index(s1, 16)
	fmt.Printf("ret=%d\n", ret)
}

// Index returns the index of the first occurence of v in s,
// or -1 if not present.
func Index[S ~[]E, E comparable](s S, v E) int {
	for i := range s {
		if v == s[i] {
			return i
		}
	}
	return -1
}
相关推荐
_.Switch7 分钟前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光11 分钟前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   12 分钟前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   13 分钟前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
编程、小哥哥15 分钟前
netty之Netty与SpringBoot整合
java·spring boot·spring
Fan_web29 分钟前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常31 分钟前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
IT学长编程1 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇1 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr2 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui