Go泛型草案設計簡明指南
女主宣言
今天小編為大家分享一篇關於Golang泛型提案的最新設計草案。涉及有關為何做出某些決策的詳細資訊,實施細節等。希望能對大家有所幫助。
PS:豐富的一線技術、多元化的表現形式,盡在“360雲端計算”,點關注哦!
最近,go團隊宣佈了針對其go泛型提案的最新設計草案。涉及有關為何做出某些決策的詳細資訊,實施細節等。
因為整個草案設計內容太多了,所以本文中,我們的目標是總結即將進行的主要更改。
我們將提供一些程式碼片段來演示主要功能。
1
泛型函式中的型別約束
不受型別引數限制的通用函式:
// package decls, imports...
func arrayOf(type T)(elems ...T) []T {
arr := []T{}
for _, el := range elems {
arr = append(arr, el)
}
return arr
}
func main() {
strs := arrayOf("one", "two", "three", "four", "five")
fmt.Println(strs)
nums := arrayOf(1, 2, 3, 4, 5)
fmt.Println(nums)
}
要對通用型別新增約束,可以要求實現給定的介面:
// package decls, imports...
// Person, who implements fmt.Stringer...
func join(type T fmt.Stringer)(tokens []T, delim string) string {
res := ""
for _, token := range tokens {
if res != "" {
res += delim
}
res += token.String()
}
return res
}
func main() {
joined := join([]Person{Person{"Mike", "Jordan"}, Person{"Dave", "Stevens"}, Person{"John", "Doe"}}, ", ")
fmt.Println(joined)
}
要指定多個型別引數,用逗號分隔:
// package decls, imports...
func mapAll(type T, R)(arr []T, mapFunc func(T) R) []R {
res := []R{}
for _, el := range arr {
res = append(res, mapFunc(el))
}
return res
}
func main() {
strs := mapAll([]int{1, 2, 3}, func(n int) string {
return strconv.Itoa(n)
})
fmt.Println(strs)
}
對多個型別引數的約束,與編寫函式引數型別相同的方式寫入:
// package decls, imports...
// Person & Animal structs, which implement fmt.Stringer...
func Concat(type T1, T2 fmt.Stringer)(f T1, s T2, delim string) string {
return f.String() + delim + s.String()
}
func main() {
res := Concat(Person{"John", "Doe"}, Animal{"Dog", "Richie"}, " loves his ")
fmt.Println(res)
}
以下是為兩個引數指定不同型別的方法:
// package decls, imports...
// Hooman & Pet interfaces...
// Person & Dog structs...
func PlayAround(type H Hooman, P Pet)(human H, pet P) {
fmt.Println("The human says:", human.Speak())
fmt.Println("And the pet responds:", pet.ProduceSound())
}
func main() {
PlayAround(Person{}, Dog{})
}
2
型別列表及可比較
可以基於一組受支援的型別來約束它們,而不是基於一組方法來約束型別。例如,可以指定接受通用型別,該通用型別只能是int或long。
這能夠 利用“小於”,“大於”之類的運算子,僅適用於Go中的基本型別:
// package decls, imports...
// Ordered is a type constraint that matches any ordered type.
// An ordered type is one that supports the <, <=, >, and >= operators.
type Ordered interface {
type int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64, uintptr,
float32, float64,
string
}
func Max(type T Ordered)(elems []T) T {
if len(elems) == 0 {
var zero T
return zero
}
max := elems[0]
for _, el := range elems {
if el > max {
max = el
}
}
return max
}
func main() {
res := Max([]int{1, 5, 3, 10, 4})
fmt.Println(res)
}
還具有一個稱為“comparable”的現成約束,該約束型別與支援==和!=運算子的約束型別相同。
// package decls, imports...
func Contains(type T comparable)(elems []T, target T) bool {
for _, elem := range elems {
if elem == target {
return true
}
}
return false
}
func main() {
fmt.Println(Contains([]int{1, 2, 3, 4, 5}, 4))
}
使用這些構造的介面-型別列表和/或類似列表只能用作型別約束,而不能用作函式引數。
3
通用型別
可以使用泛型型別定義結構。一旦指定了型別宣告,就無需為該型別的所有函式指定型別:
// package decls, imports...
type Stack(type T) struct {
buffer []T
}
func (v *Stack(T)) Push(elem T) {
v.buffer = append(v.buffer, elem)
}
func (v *Stack(T)) Pop() T {
res := v.buffer[len(v.buffer)-1]
v.buffer = v.buffer[:len(v.buffer)-1]
return res
}
func main() {
st := &Stack(int){}
st.Push(1)
st.Push(2)
st.Push(3)
fmt.Println(st.Pop())
fmt.Println(st.Pop())
fmt.Println(st.Pop())
}
也可以在介面中執行此操作。當型別約束依賴於自身時,這尤其有用。
例如。有一個T的型別約束,它需要一個Equal方法,該方法接受一個T引數:
// package decls, imports...
// Person, who implements Equaler...
type Equaler(type T) interface {
Equal(other T) bool
}
func Contains(type T Equaler)(elems []T, target T) bool {
for _, elem := range elems {
if elem.Equal(target) {
return true
}
}
return false
}
func main() {
people := []Person{Person{"Dave"}, Person{"Bob"}, Person{"Steve"}}
fmt.Println(Contains(people, Person{"Dave"}))
}
如果需要指定具有狀態修改功能的型別引數(例如,setter),則可以指定指標型別約束:
// package decls, imports...
type Setter interface {
Set(string)
}
type Settable int
// Set sets the value of *p from a string.
func (p *Settable) Set(s string) {
i, _ := strconv.Atoi(s)
*p = Settable(i)
}
func FromStrings(type *T Setter)(s []string) []T {
result := make([]T, len(s))
for i, v := range s {
// result[i] is an addressable value of type T,
// so it's OK to call Set.
result[i].Set(v)
}
return result
}
func main() {
nums := FromStrings(Settable)([]string{"1", "2", "3"})
fmt.Println(nums)
}
注意,上面的示例如何要求明確指定將在函式中使用的型別– FromStrings(Settable)…
這是因為只要型別不作為函式引數出現,編譯程式碼後,編譯器就無法推斷實際型別。因此,需要明確指定它。
總結
本文的目的是簡潔明瞭。希望它可以幫助大家快速瞭解最新的泛型草案設計。
但是,圍繞Go中的泛型進行任何單一設計選擇,背後都有很多理由。如果有興趣深入研究該主題,可以查閱官方設計草案文件。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69966971/viewspace-2700793/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 泛型最佳實踐:Go泛型設計者教你如何用泛型泛型Go
- 十、GO程式設計模式 : 泛型程式設計Go程式設計設計模式泛型
- GO語言泛型程式設計實踐Go泛型程式設計
- Go中泛型和反射比較指南Go泛型反射
- Go 泛型Go泛型
- Go 泛型之泛型約束Go泛型
- 使用 Go 泛型的函數語言程式設計Go泛型函數程式設計
- 泛型程式設計泛型程式設計
- 泛型型別(.NET 指南)泛型型別
- go泛型教程Go泛型
- go1.18泛型的簡單嘗試Go泛型
- java 泛型程式設計Java泛型程式設計
- Go 泛型的這 3 個核心設計,你都知道嗎?Go泛型
- java筆記-two-java泛型程式設計(簡記)Java筆記泛型程式設計
- 預計在 Go 1.18 中內建泛型Go泛型
- 簡明高效的 Java 併發程式設計學習指南Java程式設計
- Go 官方出品泛型教程:如何開始使用泛型Go泛型
- Java & Go 泛型對比JavaGo泛型
- Go泛型基礎使用Go泛型
- Go 1.17 泛型嚐鮮Go泛型
- 談談 "JS 和 設計泛型"JS泛型
- 泛型程式設計詳解(一)泛型程式設計
- 泛型程式設計與 OI——modint泛型程式設計
- go 1.18 泛型初體驗Go泛型
- go需要泛型的場景Go泛型
- Go 需要泛型的場景Go泛型
- 簡單易懂的 Go 泛型使用和實現原理介紹Go泛型
- 物件導向程式設計和`GP`泛型程式設計物件程式設計泛型
- Go 1.18泛型的侷限性初探Go泛型
- Go Internals: Go 反射 vs Java 泛型 vs cpp 模板Go反射Java泛型
- Go 1.18 泛型全面講解:一篇講清泛型的全部Go泛型
- Kotlin語言中的泛型設計哲學Kotlin泛型
- 泛型就這麼簡單泛型
- 其實泛型很簡單泛型
- Swift使用協議加泛型程式設計(一)Swift協議泛型程式設計
- Rust 程式設計影片教程(進階)——001 泛型Rust程式設計泛型
- 在C語言中實現泛型程式設計C語言泛型程式設計
- C語言如何實現泛型程式設計?C語言泛型程式設計