日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Go泛型:提前掌握Go泛型的基本使用

泛型,是 Go 語(yǔ)言多年來(lái)最令人興奮和根本性的變化之一。沒(méi)有泛型,很多人以此「鄙視」Go 語(yǔ)言。當(dāng)然,也有人覺(jué)得根本不需要泛型。有泛型,不代表你一定要用。平心而論,有些場(chǎng)景下,泛型還是很有必要和幫助的。

創(chuàng)新互聯(lián)建站是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護(hù)、成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站備案、服務(wù)器租用、域名與空間、軟件開(kāi)發(fā)、成都微信小程序等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運(yùn)營(yíng)推廣經(jīng)驗(yàn)的科技公司,有著多年的網(wǎng)站建站經(jīng)驗(yàn),致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開(kāi)一個(gè)面向全國(guó)乃至全球的業(yè)務(wù)窗口:建站聯(lián)系熱線:028-86922220

現(xiàn)在已經(jīng)確認(rèn),Go1.18 正式包含泛型(Go1.17 已經(jīng)可以試用,只是默認(rèn)不支持,見(jiàn)之前的文章:揚(yáng)眉吐氣:剛剛,Go 已經(jīng)默認(rèn)支持泛型了)。

不過(guò),不少人對(duì)泛型還是迷迷糊糊的。本文就嘗試用簡(jiǎn)單的術(shù)語(yǔ)解釋泛型相關(guān)的內(nèi)容。

01 什么是泛型

Go 是一門(mén)強(qiáng)類(lèi)型語(yǔ)言,意味著程序中的每個(gè)變量和值都有某種特定的類(lèi)型,例如int、string 等。在函數(shù)簽名中,我們需要對(duì)參數(shù)和返回值指定類(lèi)型,如下所示:

 
 
 
 
  1. func Add(a, b int) int 

參數(shù) a 和 b 的類(lèi)型是 int,返回值類(lèi)型也是 int,結(jié)果是 a 和 b 的和。

如果現(xiàn)在需要一個(gè)對(duì)兩個(gè) float64 求和的函數(shù),怎么辦?

大概率會(huì)出現(xiàn)類(lèi)似這樣的函數(shù):

 
 
 
 
  1. func AddFloat(a, b float64) float64 

如果有更多其他的類(lèi)型(比如字符串相加),可能需要寫(xiě)更多的對(duì)應(yīng)版本函數(shù),很不方便,也很繁瑣,一堆復(fù)制粘貼的代碼。

02 Go 中的泛型函數(shù)

如果有了泛型,上面的問(wèn)題怎么解決呢?只需要一個(gè)函數(shù)就搞定:

 
 
 
 
  1. func Add[T any](a, b T) T 

是不是很簡(jiǎn)單?不過(guò)看著有點(diǎn)暈?稍微解釋下:

  • Add 后面的 [T any],T 表示類(lèi)型的標(biāo)識(shí),any 表示 T 可以是任意類(lèi)型
  • a、b 和返回值的類(lèi)型 T 和前面的 T 是同一個(gè)類(lèi)型
  • 為什么用 [],而不是其他語(yǔ)言中的 <>,官方有過(guò)解釋?zhuān)蟾啪褪?<> 會(huì)有歧義。曾經(jīng)計(jì)劃使用 (),因?yàn)樘菀谆煜?,最后使用?[]。

這樣就表示,a、b 和返回值可以是任意類(lèi)型,但它們的類(lèi)型是同一個(gè)。那具體是什么類(lèi)型如何確定呢?根據(jù)調(diào)用時(shí)的實(shí)際參數(shù)決定。因此,我們現(xiàn)在可以這么使用:

 
 
 
 
  1. Add(1, 2) 
  2. Add(2.1, 3.2) 

不過(guò),這時(shí)候代碼會(huì)報(bào)錯(cuò)。你可以本地用 Go1.17 啟用泛型的方式試驗(yàn),也可以使用 gotip 版本,亦或直接訪問(wèn)這里試驗(yàn):https://go2goplay.golang.org/p/vTHnUA_8vOI

 
 
 
 
  1. package main 
  2.  
  3. import ( 
  4.  "fmt" 
  5.  
  6. func Add[T any](a, b T) T { 
  7.  return a + b 
  8.  
  9. func main() { 
  10.  fmt.Println(Add(1, 2)) 
  11.  fmt.Println(Add(2.1, 3.2)) 

運(yùn)行會(huì)報(bào)錯(cuò):

 
 
 
 
  1. type checking failed for main 
  2. prog.go2:8:9: invalid operation: operator + not defined for a (variable of type parameter type T) 

為什么?請(qǐng)看下文。

03 約束

很顯然,并非所有類(lèi)型都支持加法操作。因此我們需要給出約束,指定可以進(jìn)行加法操作的類(lèi)型。

上面代碼中,我們對(duì)類(lèi)型 T 使用的是 any,相當(dāng)于沒(méi)有進(jìn)行任何約束?,F(xiàn)在我們給一個(gè)約束:

 
 
 
 
  1. type Addable interface { 
  2.  type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string 

這是新語(yǔ)法,叫做類(lèi)型列表(type list)。

首先,Addable 重用了接口語(yǔ)法,即 interface 關(guān)鍵字,表示約束,具體約束的類(lèi)型通過(guò) type 指定,多個(gè)用逗號(hào)分隔。

現(xiàn)在 Add 函數(shù)中 T 的約束從 any 改為 Addable:

 
 
 
 
  1. func Add[T Addable](a, b T "T Addable") T { 
  2.  return a + b 

現(xiàn)在再次運(yùn)行:https://go2goplay.golang.org/p/4J52QmGrc-M,發(fā)現(xiàn)正常了。而且還支持字符串、復(fù)數(shù)等:

 
 
 
 
  1. Add("polaris", "xu") 

可見(jiàn),約束可以是任意接口類(lèi)型。(any 相當(dāng)于空接口)

還有另外一種場(chǎng)景:可比較。比如 map 中的 key 要求是可比較的。比如下面的代碼:

 
 
 
 
  1. func findFunc[T any](a []T, v T "T any") int { 
  2.  for i, e := range a { 
  3.   if  e == v { 
  4.       return i 
  5.     } 
  6.  } 
  7.  return -1 
  8.  } 

T 的約束是任意類(lèi)型,而實(shí)際上并非所有類(lèi)型都是可比較的。怎么辦?我們當(dāng)然可以向上面 Addable 一樣定義一個(gè)約束,但為了方便,Go 內(nèi)置提供了一個(gè) comparable 約束,表示可比較的。參考下面代碼:

 
 
 
 
  1. package main 
  2.  
  3. func findFunc[T comparable](a []T, v T "T comparable") int { 
  4.  for i, e := range a { 
  5.   if e == v { 
  6.    return i 
  7.   } 
  8.  } 
  9.  return -1 
  10.  
  11. func main() { 
  12.  print(findFunc([]int{1, 2, 3, 4, 5, 6}, 5)) 

04 constraints 包

寫(xiě)泛型代碼時(shí),約束挺常見(jiàn)。再看一個(gè)例子,從切片中找出最大值:

 
 
 
 
  1. func Max[T any](input []T "T any") (max T) { 
  2.     for _, v := range input { 
  3.         if v > max { 
  4.             max = v 
  5.         } 
  6.     } 
  7.     return 

但運(yùn)行會(huì)報(bào)錯(cuò):

 
 
 
 
  1. fmt.Println(Max([]int{1, 4, 2, 10})) 
  2. // cannot compare v > max (operator > not defined for T) 

這時(shí),我們自然想到使用上面 Add 函數(shù)類(lèi)似的辦法,自定義一個(gè)約束:Ordered,把可能的類(lèi)型都列上。

 
 
 
 
  1. type Ordered interface { 
  2.     type int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, string 

因?yàn)檫@樣的需求挺常見(jiàn)的,為了方面,官方提供了一個(gè)新包:constraints,預(yù)定義了一些約束,具體查看:https://github.com/golang/go/issues/45458。

有了它,不需要自定義這個(gè) Ordered 約束,而是使用 constraints 包中的,即:

 
 
 
 
  1. func Max[T constraints.Ordered](input []T "T constraints.Ordered") (max T) 

05 泛型類(lèi)型

上面,我們介紹了泛型函數(shù):即函數(shù)可以接受任意類(lèi)型。注意和 interface{} 這樣的任意類(lèi)型區(qū)分開(kāi),泛型中的類(lèi)型,在函數(shù)內(nèi)部并不需要做任何類(lèi)型斷言和反射的工作,在編譯期就可以確定具體的類(lèi)型。

我們知道,Go 支持自定義類(lèi)型,比如標(biāo)準(zhǔn)庫(kù) sort 包中的 IntSlice:

 
 
 
 
  1. type IntSlice []int 

此外,還有 StringSlice、Float64Slice 等,一堆重復(fù)代碼。如果我們能夠定義泛型類(lèi)型,就不需要定義這么多不同的類(lèi)型了。比如:

 
 
 
 
  1. type Slice[T any] []T 

能看懂吧。

在使用時(shí),針對(duì) int 類(lèi)型,就是這樣:

 
 
 
 
  1. x := Slice[int]{1, 2, 3} 

如果作為函數(shù)參數(shù),這么使用:

 
 
 
 
  1. func PrintSlice[T any](b Slice[T] "T any") 

如果為這個(gè)類(lèi)型定義方法,則是這樣:

 
 
 
 
  1. func (b Slice[T]) Print() 

也就是說(shuō),Slice[T] 作為整體存在。

當(dāng)然,泛型類(lèi)型也可以做類(lèi)型約束,而不是 any 類(lèi)型:

 
 
 
 
  1. type Slice[T comparable] []T 

06 總結(jié)

通過(guò)本文的講解,相信你對(duì) Go 泛型有了一個(gè)基本的掌握。

Go1.18 會(huì)包含不少泛型相關(guān)的標(biāo)準(zhǔn)庫(kù),包括對(duì)現(xiàn)有標(biāo)準(zhǔn)庫(kù)的泛型支持,這是目前 Go 官方的重要工作。

今天開(kāi)一個(gè)頭,后續(xù)會(huì)不斷分享 Go 泛型更多的內(nèi)容,大家一起提前掌握 Go 泛型。

本文轉(zhuǎn)載自微信公眾號(hào)「polarisxu」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系polarisxu公眾號(hào)。


網(wǎng)站名稱(chēng):Go泛型:提前掌握Go泛型的基本使用
URL標(biāo)題:http://www.5511xx.com/article/cohohoc.html