🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁
🦄 博客首页——🐅🐾猫头虎的博客🎐
🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐
🌊 《100天精通Golang(基础入门篇)》 🐅 学会Golang语言,畅玩云原生,走遍大小厂~💐
🐅🐾猫头虎建议Go程序员必备技术栈一览表📖:
☁️🐳
Go语言开发者必备技术栈☸️
:
🐹 GoLang | 🌿 Git | 🐳 Docker | ☸️ Kubernetes | 🔧 CI/CD | ✅ Testing | 💾 SQL/NoSQL | 📡 gRPC | ☁️ Cloud | 📊 Prometheus | 📚 ELK Stack
🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🐅🐾🍁🐥
文章目录
- 🐅🐾猫头虎建议Go程序员必备技术栈一览表📖:
- 2023年9月26日 Go生态洞察:深入解析类型参数
- 🐾 正文内容
- 🐈 `slices`包函数签名
- 🐈 简单的克隆实现
- 🐈 灵活的克隆实现
- 🐈 底层类型约束
- 🐈 类型推断
- 🐈 类型参数的解构
- 🐾 总结
- 原创声明
-
原创作者: 猫头虎
-
作者wx: Libin9iOak
-
作者公众号: 猫头虎技术团队
2023年9月26日 Go生态洞察:深入解析类型参数
🐾 摘要
大家好,我是猫头虎,今天我们要探讨的是Go语言中类型参数的构造和使用。通过深入分析slices.Clone
函数,我们将理解类型参数在Go泛型中的作用和重要性。这不仅是一个技术深度话题,而且对于深入理解Go语言的泛型系统至关重要。
🐾 引言
在Go 1.18的引入泛型之后,类型参数成为了Go语言的一个新亮点。它们提供了编写更加灵活和可复用代码的能力。本文将通过Clone
函数的例子,展示如何有效地使用类型参数来增强代码的通用性和灵活性。
🐾 正文内容
🐈 slices
包函数签名
Clone
函数非常简单:它可以复制任何类型的切片。
func Clone[S ~[]E, E any](s S) S {return append(s[:0:0], s...)
}
这个函数之所以有效,是因为对零容量的切片进行追加操作会分配一个新的底层数组。函数体实际上比函数签名更短,这部分是因为体本身简短,但也因为签名较长。接下来,我们将解释为什么签名是这样写的。
🐈 简单的克隆实现
我们首先编写一个简单的通用Clone
函数。这并不是slices
包中的那一个。我们希望接受任何元素类型的切片,并返回一个新切片。
func Clone1[E any](s []E) []E {// body omitted
}
泛型函数Clone1
有一个类型参数E
。它接受一个类型为E
的切片参数s
,并返回同类型的切片。这个签名对熟悉Go中泛型的人来说很直接。
然而,这里有一个问题。在Go中,命名的切片类型不常见,但人们确实会使用它们。
// MySlice 是一个具有特殊String方法的字符串切片。
type MySlice []string// String 返回MySlice值的可打印版本。
func (s MySlice) String() string {return strings.Join(s, "+")
}
假设我们想要复制一个MySlice
,然后获取其排序后的可打印版本。
func PrintSorted(ms MySlice) string {c := Clone1(ms)slices.Sort(c)return c.String() // 编译失败
}
不幸的是,这不起作用。编译器报告错误:
c.String undefined (type []string has no field or method String)
🐈 灵活的克隆实现
为了解决这个问题,我们必须编写一个版本的Clone
,它返回与其参数相同的类型。如果我们做到了这一点,那么当我们用MySlice
类型的值调用Clone
时,它将返回MySlice
类型的结果。
我们知道它应该是这样的:
func Clone2[S ?](s S) S // 无效
这个Clone2
函数返回与其参数相同类型的值。
🐈 底层类型约束
如错误消息所示,答案是添加一个~
。
func Clone5[S ~[]E, E any](s S) S
再次强调,用[S []E, E any]
这样的类型参数和约束表示,意味着S
的类型参数可以是任何未命名的切片类型,但
不能是定义为切片字面量的命名类型。用[S ~[]E, E any]
,加上~
,意味着S
的类型参数可以是任何底层类型为切片类型的类型。
🐈 类型推断
现在我们已经解释了slices.Clone
的签名,让我们看看如何通过类型推断简化对slices.Clone
的使用。
func Clone[S ~[]E, E any](s S) S
调用slices.Clone
时,将传递一个切片给参数s
。类型推断将允许编译器推断出类型参数S
是传递给Clone
的切片的类型。然后,类型推断足够强大,可以看出E
的类型参数是传递给S
的类型参数的元素类型。
🐈 类型参数的解构
我们在这里使用的一般技术,即使用另一个类型参数E
定义一个类型参数S
,是一种在泛型函数签名中解构类型的方法。通过解构类型,我们可以命名并约束类型的所有方面。
例如,这是maps.Clone
的签名:
func Clone[M ~map[K]V, K comparable, V any](m M) M
就像slices.Clone
一样,我们使用一个类型参数来表示参数m
的类型,然后使用另外两个类型参数K
和V
来解构该类型。
在maps.Clone
中,我们将K
约束为可比较的,因为这是映射键类型所必需的。我们可以根据喜好约束组成类型。
func WithStrings[S ~[]E, E interface { String() string }](s S) (S, []string)
这表示WithStrings
的参数必须是一个切片类型,其元素类型具有String
方法。
由于所有Go类型都可以从组成类型构建,我们总是可以使用类型参数来解构这些类型,并根据我们的喜好对它们进行约束。
🐾 总结
总的来说,类型参数在Go泛型中扮演着至关重要的角色。通过精心设计的函数签名和有效利用类型推断,我们可以编写更灵活、更通用的代码。希望这篇文章能帮助你更好地理解Go中的泛型。这篇文章由猫头虎的Go生态洞察专栏收录,更多详情请点击这里。
关键点 | 描述 |
---|---|
类型参数使用 | 使用类型参数构建灵活通用的函数 |
slices.Clone 分析 | 分析Clone 函数的类型参数和其用法 |
底层类型约束 | 理解底层类型的约束和它们的应用 |
类型推断 | 探索类型推断在泛型编程中的作用 |
下一篇预告: 下一篇文章将深入探讨Go语言中的类型推断——《关于类型推断的一切——还有更多》。我们将继续深入泛型编程的精髓,探索类型推断如何简化我们的编码过程。敬请期待!�
原创声明
======= ·
-
原创作者: 猫头虎
-
作者wx: Libin9iOak
-
作者公众号: 猫头虎技术团队
学习 | 复习 | Go生态 |
---|---|---|
✔ | ✔ | ✔ |
本文为原创文章,版权归作者所有。未经许可,禁止转载、复制或引用。
作者保证信息真实可靠,但不对准确性和完整性承担责任。
未经许可,禁止商业用途。
如有疑问或建议,请联系作者。
感谢您的支持与尊重。
点击
下方名片
,加入IT技术核心学习团队。一起探索科技的未来,洞察Go生态,共同成长。