Go 泛型玩出花,详解新提案 Switch Type!

开发 后端
新的提案内容是希望增加一个新的变种语句,允许在 switch 语句的类型中使用泛型时,能够进一步便捷的约束其类型参数。

[[440023]]

本文转载自微信公众号「脑子进煎鱼了」,作者陈煎鱼。转载本文请联系脑子进煎鱼了公众号。

大家好,我是煎鱼。

前面写过好几篇 Go 泛型的语法、案例介绍,新的一手 Go 消息。实际上,随着一些提案被接受,新的提案也逐渐冒出。

这不,我发现有了泛型后,大家可以更进一步玩出花来了。看到了一个 ”新“ 提案《proposal: spec: generics: type switch on parametric types[1]》,讲的就是增加泛型后的参数类型上的类型开关诉求。

跟着煎鱼一起掌握新的 Go 知识吧!

新提案

新的提案内容是希望增加一个新的变种语句,允许在 switch 语句的类型中使用泛型时,能够进一步便捷的约束其类型参数。

例如:

  1. switch type T { 
  2. case A1: 
  3. case A2, A3: 
  4.    ... 

也就是 switch-type 语句的 T 类型可以是一个泛型的类型参数,case 所对应的的类型可以是任何类型,包括泛型的约束类型。

假设类型 T 的类型有可能是以下类型:

  1. interface{ 
  2.     C 
  3.     A 

可以借助泛型的近似元素来约束:

  1. interface{ 
  2.     C 
  3.     A1 | A2 | ... | An 

甚至还可以在 case 上有新的写法:

  1. case interface {~T}: 

在支持泛型后,switch 在 type 和 case 上会存在很多种可能性,需要进行具体的特性支持,这个提案就是为此出现。

实际案例

案例一:多类型元素

  1. type Stringish interface { 
  2.  string | fmt.Stringer 
  3.  
  4. func Concat[S Stringish](x []S "S Stringish") string { 
  5.     switch type S { 
  6.     case string: 
  7.         ... 
  8.     case fmt.Stringer: 
  9.         ... 
  10.     } 
  11.  } 

类型 S 能够支持 string 和 fmt.Stringer 类型,case 配套对应实现。

案例二:近似元素

  1. type Constraint interface { 
  2.     ~int | ~int8 | ~string 
  3.  
  4. func ThisSyntax[T Constraint]( "T Constraint") { 
  5.     switch type T { 
  6.     case ~int | ~int8: 
  7.         ... 
  8.     case ~string: 
  9.         ... 
  10.     } 
  11.  
  12. func IsClearerThanThisSyntax[T Constraint]( "T Constraint") { 
  13.     switch type T { 
  14.     case interface{~int | ~int8 }: 
  15.         ... 
  16.     case interface{ ~string }: 
  17.         ... 
  18.     } 

类型 T 可能有很多类型,程序中用到了近似元素,也就是基础类型是 int、int8、string,这些类型中的任何一种都能够满足这个约束。

为此,switch-type 支持了,case 也要配套支持该特性。

争议点

看到这里可能大家也想到了,这个味道很似曾相识,好像某个语法能够支持。因此,这个提案下最有争议的,就是与原有的类型断言的重复。

原有的类型断言如下:

  1. switch T.(type) { 
  2. case string: 
  3.    ... 
  4. default
  5.    ... 

新的类型判别如下:

  1. switch type T { 
  2. case A1: 
  3. case A2, A3: 
  4.    ... 

这么咋一看,其实类型断言的完全可以取代新的,那岂不是重复建设,造轮子了?

其实是没有完全取代的。差异点如下:

  1. type ApproxString interface { ~string } 
  2.  
  3. func F[T ApproxString](v T "T ApproxString") { 
  4.     switch (interface{})(v).(type) { 
  5.     case string: 
  6.         fmt.Println(v) 
  7.     default
  8.         panic("脑子没进煎鱼"
  9.     } 
  10.  
  11. type MyString string 
  12.  
  13. func main() { 
  14.     F(MyString("脑子进煎鱼了"))  

看出来差别在哪了吗,答案是什么?

答案是:会抛出恐慌(panic)。

你可能纠结了,问题出在哪里?这传入的 ”脑子进煎鱼了“ 的类型是 MyString,他的基础类型是 string 类型,也满足 ApproxString 类型的近似类型 ~string 的要求,怎么就不行了...

根本原因是因为他的类型是 interface,而非 string 类型。所以走到了 defalut 分支的恐慌。

总结

今天给大家介绍了 Go 泛型的最新消息,在上一个提案被合并后,该提案也有一些新的动静,不过 Go 官方表态,会等熟练掌握泛型实践后,再继续推动该提案。

我相信原有的 switch.(type) 和 switch type 很大概率在 Go 底层会变成同一个逻辑块处理,再逐渐过渡。

这个提案的目的还是为了解决若干引入泛型后,所带入的 BUG/需求,正正是需要新的语法结构来解决的。

你对此有什么看法呢,欢迎在评论区留言和交流:)

参考资料

[1]proposal: spec: generics: type switch on parametric types: https://github.com/golang/go/issues/45380

 

责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2021-08-09 10:36:20

GoSlices Maps

2021-01-14 05:20:48

Go语言泛型

2011-03-21 16:26:28

java泛型

2021-02-05 16:26:08

Go开发者提案

2021-09-29 18:17:30

Go泛型语言

2021-12-14 10:54:31

TopK面试排序法

2021-02-25 15:51:41

Go语言模糊测试功能

2023-12-27 08:03:53

Go优化代码

2021-06-18 08:25:42

Java泛型通配符

2022-03-28 13:34:26

Go泛型部署泛型

2021-11-27 22:20:13

SlicesGo泛型

2023-11-03 14:02:04

Go切片泛型库

2023-11-29 08:19:45

Go泛型缺陷

2011-04-13 09:16:55

泛型

2021-08-04 12:26:00

Postman工具频率

2022-11-15 09:16:59

2021-12-15 10:23:56

Go 1.18 Bet语言泛型

2021-12-05 23:45:23

Go泛型Maps

2022-04-15 09:55:59

Go 泛型Go 程序函数

2009-07-30 14:00:21

ASP.NET 2.0
点赞
收藏

51CTO技术栈公众号