如何使用泛型 Go 實例化型別參數的非零指標?
php小編西瓜將為您介紹如何在Go語言中使用泛型實例化類型參數的非零指標。在Go語言中,泛型是一種強大的特性,可以增加程式碼的靈活性和重複使用性。當我們需要在泛型函數或方法中實例化一個非零指標時,可以使用型別斷言和反射來實現。透過使用這些技術,我們可以在運行時根據類型參數的具體類型來建立一個非零指標實例,從而實現泛型的靈活性和通用性。下面我們來詳細了解具體的實作方法。
問題內容
現在 golang/go:master
上提供了類型參數,我決定嘗試一下。看來我遇到了在類型參數提案中找不到的限制。 (或者我一定錯過了)。
我想寫一個函數,它傳回帶有介面類型約束的泛型類型值的切片。如果傳遞的類型是帶有指標接收器的實現,我們如何實例化它?
type SetGetter[V any] interface { Set(V) Get() V } // SetGetterSlice turns a slice of type V into a slice of type T, // with T.Set() called for each entry in values. func SetGetterSlice[V any, T SetGetter[V]](values []V) []T { out := make([]T, len(values)) for i, v := range values { out[i].Set(v) // panic if T has pointer receiver! } return out }
當使用*Count
類型作為T
呼叫上述SetGetterSlice()
函數時,此程式碼將在呼叫Set(v)
時出現混亂。 (Go2go 遊樂場)毫不奇怪,因為基本上程式碼創建了 nil
指標的切片:
// Count implements SetGetter interface type Count struct { x int } func (c *Count) Set(x int) { c.x = x } func (c *Count) Get() int { return c.x } func main() { ints := []int{1, 2, 3, 4, 5} sgs := SetGetterSlice[int, *Count](ints) for _, s := range sgs { fmt.Println(s.Get()) } }
同一問題的變體
這個想法行不通,我似乎找不到任何簡單的方法來實例化指向的值。
out[i] = new(T)
將導致編譯失敗,因為它傳回*T
,其中類型檢查器希望查看T
。- 呼叫
*new(T)
進行編譯,但會導致相同的執行時間恐慌,因為new(T)
傳回**Count
在這種情況下,其中指向Count
的指標仍然是nil
。 - 將傳回類型變更為指向
T
的指標片段將導致編譯失敗:
func SetGetterSlice[V any, T SetGetter[V]](values []V) []*T { out := make([]*T, len(values)) for i, v := range values { out[i] = new(T) out[i].Set(v) // panic if T has pointer receiver } return out } func main() { ints := []int{1, 2, 3, 4, 5} SetGetterSlice[int, Count](ints) // Count does not satisfy SetGetter[V]: wrong method signature }
解決方法
到目前為止我發現的唯一解決方案是要求將建構函數傳遞給泛型函數。但這感覺不對,而且有點乏味。如果 func F(T interface{})() []T
是完全有效的語法,為什麼需要這樣做?
func SetGetterSlice[V any, T SetGetter[V]](values []V, constructor func() T) []T { out := make([]T, len(values)) for i, v := range values { out[i] = constructor() out[i].Set(v) } return out } // ... func main() { ints := []int{1, 2, 3, 4, 5} SetGetterSlice[int, *Count](ints, func() *Count { return new(Count) }) }
摘要
我的問題(按優先順序排列):
- 我是否忽略了一些顯而易見的事情?
- 這是 Go 中泛型的限制嗎?這已經是最好的了嗎?
- 此限制是否已知,或者我應該在 Go 專案中提出問題嗎?
解決方法
基本上,您必須在約束中新增一個類型參數,以使 T
可轉換為其指標類型。在最基本的形式中,該技術如下所示(帶有匿名約束):
func Foo[T any, PT interface { *T; M() }]() { p := PT(new(T)) p.M() // calling method on non-nil pointer }
遊樂場:https://www.php.cn/link/24aef8cb3281a2422a59b51659f1ad2e
<小时>#逐步解決方案
#您的限制 SetGetter
已經宣告了型別參數 V
,因此我們稍微修改上面的範例:
// V is your original type param // T is the additional helper param type SetGetter[V any, T any] interface { Set(V) Get() V *T }
接著定義 SetGetterSlice
函數,其型別參數為 T any
,其目的只是實例化限制 SetGetter
。
然後您就可以將表達式 &out[i]
轉換為指標類型,並成功呼叫指標接收器上的方法:
// T is the type with methods with pointer receiver // PT is the SetGetter constraint with *T func SetGetterSlice[V any, T any, PT SetGetter[V, T]](values []V) []T { out := make([]T, len(values)) for i, v := range values { // out[i] has type T // &out[i] has type *T // PT constraint includes *T p := PT(&out[i]) // valid conversion! p.Set(v) // calling with non-nil pointer receiver } return out }
完整程式:
CFE57E536C89530D9A8C38E10967A10D這變得更加冗長,因為SetGetterSlice
現在需要三個型別參數:原始V
加上#T
(有指標接收器的型別)和PT
(新限制)。然而,當您呼叫函數時,您可以省略第三個- 透過型別推斷,實例化PT SetGetter[V,T]
所需的型別參數V
和T
都是已知的:
SetGetterSlice[int, Count](ints)
遊樂場:https://www.php.cn/link/6b061fc28f7473418a006dfa832708b1
#以上是如何使用泛型 Go 實例化型別參數的非零指標?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Bootstrap 圖片居中方法多樣,不一定要用 Flexbox。如果僅需水平居中,text-center 類即可;若需垂直或多元素居中,Flexbox 或 Grid 更合適。 Flexbox 兼容性較差且可能增加複雜度,Grid 則更強大且學習成本較高。選擇方法時應權衡利弊,並根據需求和偏好選擇最適合的方法。

C35 的計算本質上是組合數學,代表從 5 個元素中選擇 3 個的組合數,其計算公式為 C53 = 5! / (3! * 2!),可通過循環避免直接計算階乘以提高效率和避免溢出。另外,理解組合的本質和掌握高效的計算方法對於解決概率統計、密碼學、算法設計等領域的許多問題至關重要。

Go語言中使用RedisStream實現消息隊列時類型轉換問題在使用Go語言與Redis...

網頁批註功能的Y軸位置自適應算法本文將探討如何實現類似Word文檔的批註功能,特別是如何處理批註之間的間�...

GoLand中自定義結構體標籤不顯示怎麼辦?在使用GoLand進行Go語言開發時,很多開發者會遇到自定義結構體標籤在�...

Go編程中的資源管理:Mysql和Redis的連接與釋放在學習Go編程過程中,如何正確管理資源,特別是與數據庫和緩存�...

std::unique 去除容器中的相鄰重複元素,並將它們移到末尾,返回指向第一個重複元素的迭代器。 std::distance 計算兩個迭代器之間的距離,即它們指向的元素個數。這兩個函數對於優化代碼和提升效率很有用,但也需要注意一些陷阱,例如:std::unique 只處理相鄰的重複元素。 std::distance 在處理非隨機訪問迭代器時效率較低。通過掌握這些特性和最佳實踐,你可以充分發揮這兩個函數的威力。
