我有幾個需要以相同方式處理的自定義型別。這似乎是泛型的完美用途。在這個程序中,我需要在型別的實體上呼叫方法,這些方法回傳相同型別的不同實體,然后我需要在這些回傳的實體上呼叫方法,我無法作業。出于這個問題的目的,我編造了一組更簡單的型別和一個程序來舉例說明我遇到的問題。
這是一個沒有泛型的作業示例,它顯示了型別 (Circle和Square),以及一個程序 ( .Bigger().Smaller()),稍后我將嘗試將其抽象為泛型函式(在線演示):
package main
import (
"fmt"
)
type Circle struct{ r float64 }
func NewCircle(r float64) *Circle { return &Circle{r: r} }
func (c *Circle) Radius() float64 { return c.r }
func (c *Circle) Bigger() *Circle { return &Circle{r: c.r 1} }
func (c *Circle) Smaller() *Circle { return &Circle{r: c.r - 1} }
type Square struct{ s float64 }
func NewSquare(s float64) *Square { return &Square{s: s} }
func (s *Square) Side() float64 { return s.s }
func (s1 *Square) Bigger() *Square { return &Square{s: s1.s 1} }
func (s1 *Square) Smaller() *Square { return &Square{s: s1.s - 1} }
func main() {
fmt.Println(NewCircle(3).Bigger().Smaller().Radius()) // prints 3
fmt.Println(NewSquare(6).Bigger().Smaller().Side()) // prints 6
}
我做一個泛型函式的第一件事是定義一個型別約束:
type ShapeType interface {
*Circle | *Square
}
我將 a 傳遞ShapeType給一個process方法,并且我需要能夠呼叫ShapeType實體上的方法,所以我需要定義另一個型別約束,它指定可以在 a 上調??用的方法ShapeType:
type Shape[ST ShapeType] interface {
Bigger() ST
Smaller() ST
}
有了這些,我可以寫一個process方法(在線演示):
func process[ST ShapeType](s Shape[ST]) ST {
return s.Bigger().Smaller()
}
然而,這無法編譯,因為的回傳值s.Bigger()是 a ST,而不是 a Shape[ST],所以 go 不知道它可以呼叫Smaller()的回傳值s.Bigger()。用 Go 的話來說:
s.Bigger().Smaller 未定義(ST 型別沒有更小的欄位或方法)
如果Bigger()并且Smaller()沒有回傳其接收器型別的實體,我可以寫:
type Shape interface {
*Circle | *Square
Bigger()
Smaller()
}
func process[S Shape](x S) S {
x.Bigger().Smaller()
return x // I guess we wouldn't even have to return x, but just for example's sake
}
相反,我需要寫:
type Shape interface {
*Circle | *Square
Bigger() Shape
Smaller() Shape
}
并且看起來 go 不喜歡自參考型別約束。
如果可以將具體型別斷言/轉換為它符合的介面,那么我可以讓它作業,但似乎不可能做到這一點(在線演示):
func process[ST ShapeType](s Shape[ST]) ST {
s1 := s.Bigger()
s2 := s1.(Shape[ST]) // go is not happy here
return s2.Smaller()
}
為此,go 說:
不能對型別引數值 s1 使用型別斷言(受 ShapeType 約束的 ST 型別變數)
我不知道還能嘗試什么。
是否可以使用泛型處理這些型別?如果是這樣,怎么做?
uj5u.com熱心網友回復:
將您嘗試的兩個介面組合在一起:
type Shape[ST any] interface {
*Circle | *Square
Bigger() ST
Smaller() ST
}
process然后用型別引數本身實體化約束:
func process[ST Shape[ST]](s ST) ST {
return s.Bigger().Smaller()
}
*Circle | *Square添加union 元素Shape[ST any]意味著只有這兩種型別才能實作介面- 然后在方法簽名中使用型別引數,如
Bigger() ST,意味著傳遞的任何型別都有一個回傳自身的方法。
如果你想保持ShapeType一個單獨的介面,你可以寫成Shape:
type Shape[ST any] interface {
ShapeType
Bigger() ST
Smaller() ST
}
您還可以使用process帶有型別推斷的方法,沒有任何問題:
func main() {
c1 := NewCircle(3)
c2 := process(c1)
fmt.Println(c2.Radius()) // prints 3 as expected
fmt.Printf("%T\n", c2) // *main.Circle
s1 := NewSquare(6)
s2 := process(s1)
fmt.Println(s2.Side()) // prints 6 as expected
fmt.Printf("%T\n", s2) // *main.Square
}
最后的游樂場:https ://go.dev/play/p/_mR4wkxXupH
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/510450.html
標籤:去仿制药约束
上一篇:將多種方法重構為一個通用方法
