深入理解Go泛型里的~[]E

Written by

in

文章目录
  • 这个 ~ 符号是关键,它被称为“类型近似”(Type Approximation)。它的作用是放宽类型约束,从“必须是这个确切类型”变为“底层实现是这个类型就行”。
  • Go 允许我们基于现有类型创建新的“具名类型”(Named Type)。例如: // 我们定义了一个新的类型 MyIntSlice,它的底层实现是一个 int 切片 type MyIntSlice []int 在 Go 严格的类型系统中,MyIntSlice 和 []int 是两种完全不同的类型。 问题来了:假设你写了一个泛型函数,希望它能处理任何类型的切片: // 版本1:没有 `~` func processSlice[S []E, E any](s S) { // … 对切片 s 进行操作 } var a []int = []int{1, 2} var b MyIntSlice = []int{3, 4} processSlice(a) // 正确,因为 a 的类型就是 []int processSlice(b) // 编译错误! processSlice(b) 会编译失败,因为 b 的类型是 MyIntSlice,它不等于 []E 这个约束(在这里 []E 被推断为 []int)。编译器会告诉你:MyIntSlice does not implement []int。
  • 通过添加 ~,你告诉编译器:“我不在乎它的具体名字是什么,只要它的底层本质是个切片就行”。 // 版本2:使用 `~` func processSliceFixed[S ~[]E, E any](s S) { // … } var a []int = []int{1, 2} var b MyIntSlice = []int{3, 4} processSliceFixed(a) // 正确,[]int 的底层类型是 []int processSliceFixed(b) // 正确,MyIntSlice 的底层类型也是 []int 现在,processSliceFixed 函数既能接受原生的 []int,也能接受我们自定义的 MyIntSlice,因为它们的底层类型都满足 []E 的模式。
  • 语法 含义 类比 []E 类型必须就是 []E。 只认官方发的“身份证”。 ~[]E 类型的底层实现必须是 []E。 不但认“身份证”,也认基于身份证信息办理的、功能一样的“市民卡”。 所以,当你希望你的泛型函数更具通用性,能够处理基于切片、map、或其他基础类型创建的自定义类型时,~ 就是必不可少的工具。 到此这篇关于深入理解Go泛型里的 ~[]E的文章就介绍到这了,更多相关Go泛型 ~[]E内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Go泛型中的~struct{}的具体使用
  • 目录
    • 1. 核心概念:~符号
    • 2. 为什么需要它?解决什么问题?
    • 3.~如何解决问题
    • 精辟总结

    一句话概括:~[]E 是一种类型约束,它允许函数接受任何“底层类型”为切片 []E 的类型,而不仅仅是原生切片 []E 本身。

    下面是详细分解说明:

    这个 ~ 符号是关键,它被称为“类型近似”(Type Approximation)。它的作用是放宽类型约束,从“必须是这个确切类型”变为“底层实现是这个类型就行”。

    Go 允许我们基于现有类型创建新的“具名类型”(Named Type)。例如:

    // 我们定义了一个新的类型 MyIntSlice,它的底层实现是一个 int 切片
    type MyIntSlice []int
    

    在 Go 严格的类型系统中,MyIntSlice[]int 是两种完全不同的类型。

    问题来了:假设你写了一个泛型函数,希望它能处理任何类型的切片:

    // 版本1:没有 `~`
    func processSlice[S []E, E any](s S) {
        // ... 对切片 s 进行操作
    }
    
    var a []int = []int{1, 2}
    var b MyIntSlice = []int{3, 4}
    
    processSlice(a) // 正确,因为 a 的类型就是 []int
    processSlice(b) // 编译错误!
    

    processSlice(b) 会编译失败,因为 b 的类型是 MyIntSlice,它不等于 []E 这个约束(在这里 []E 被推断为 []int)。编译器会告诉你:MyIntSlice does not implement []int

    通过添加 ~,你告诉编译器:“我不在乎它的具体名字是什么,只要它的底层本质是个切片就行”。

    // 版本2:使用 `~`
    func processSliceFixed[S ~[]E, E any](s S) {
        // ...
    }
    
    var a []int = []int{1, 2}
    var b MyIntSlice = []int{3, 4}
    
    processSliceFixed(a) // 正确,[]int 的底层类型是 []int
    processSliceFixed(b) // 正确,MyIntSlice 的底层类型也是 []int
    

    现在,processSliceFixed 函数既能接受原生的 []int,也能接受我们自定义的 MyIntSlice,因为它们的底层类型都满足 []E 的模式。

    语法 含义 类比
    []E 类型必须就是 []E。 只认官方发的“身份证”。
    ~[]E 类型的底层实现必须是 []E。 不但认“身份证”,也认基于身份证信息办理的、功能一样的“市民卡”。

    所以,当你希望你的泛型函数更具通用性,能够处理基于切片、map、或其他基础类型创建的自定义类型时,~ 就是必不可少的工具。

    到此这篇关于深入理解Go泛型里的 ~[]E的文章就介绍到这了,更多相关Go泛型 ~[]E内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • Go泛型中的~struct{}的具体使用

    站内搜索