我已經開始嘗試 Go 泛型。有沒有辦法定義泛型型別,例如:一個方法不需要用指標接收器呼叫,另一個需要用指標接收器呼叫。
例子:
type MapKey interface {
comparable
}
type Unmarshaller[T any] interface {
UnmarshalJSON(b []byte) error
*T
}
type Marshaller[T any] interface {
MarshalJSON() ([]byte, error)
}
type MapValue[T any] interface {
Marshaller[T]
Unmarshaller[T]
}
type Map[T any, K MapKey, V MapValue[T]] struct {
_ K
_ V
}
func (m Map[K, V]) Save(k K, v V) error {
_, _ = v.MarshalJSON()
return nil
}
func (m Map[K, V]) Get(k K) (value V, err error) {
v := new(V)
err = v.UnmarshalJSON(m.bytesFromKey(k))
return *v, nil
}
// here I need to make sure V is actually a pointer so that UnmarshalJSON correctly propagates to the caller of GetTo and no copy is made of V
func (m Map[K, V]) GetTo(k K, v V) error {
bytesValue := m.kv.Get(m.bytesFromKey(k))
return v.UnmarshalJSON(v)
}
錯誤:
./map_generic.go:26:16: V has no constraints
./map_generic.go:27:11: v.MarshalJSON undefined (type bound for V has no method MarshalJSON)
./map_generic.go:31:16: V has no constraints
./map_generic.go:33:10: v.UnmarshalJSON undefined (type *V has no field or method UnmarshalJSON)
uj5u.com熱心網友回復:
我還沒有找到一種方法來限制一個介面有一個指標方法和一個非指標方法。但是我找到了一種方法來擁有一個結構型別,該型別具有接受 T 或 *T 的方法。
我不得不拆分介面(Marshaller、Unmarshaller)并限制它們使用相同的型別,然后Map型別定義同時使用兩者。
這是代碼 (GOVERSION="devel go1.18-c239790 Sat Nov 13 03:33:55 2021 0000")
package storage
// Marshaller has T type parameter
type Marshaller[T interface{}] interface {
MarshalJSON() ([]byte, error)
}
// Unmarshaller has T type parameter and we force it to be a pointer
type Unmarshaller[T interface{}] interface {
UnmarshalJSON(b []byte) error
*T
}
// Map so here we need T, and we force Marshaller and Unmarshaller to be using the same type T
type Map[T any, K comparable, MV Marshaller[T], UV Unmarshaller[T]] struct {
}
func NewMap[T any, K comparable, MV Marshaller[T], UV Unmarshaller[T]]() Map[T, K, MV, UV] {
return Map[T, K, MV, UV]{}
}
// Save accepts the non pointer version of T to use for MarshalJSON
func (m Map[T, K, MV, UV]) Save(k K, v MV) {
v.MarshalJSON()
}
// GetTo accepts the pointer version of T to use for UnmarshalJSON
func (m Map[T, K, MV, UV]) GetTo(k K, v UV) {
v.UnmarshalJSON(nil)
}
這是斷言我們可以強制某些方法接受或不接受相同型別的指標的測驗檔案。
package storage
import (
"testing"
)
type x struct {
}
func (x *x) UnmarshalJSON(b []byte) error {
return nil
}
func (x x) MarshalJSON() ([]byte, error) {
return nil, nil
}
// This will compile
func TestMarshalNoPointer(t *testing.T) {
m := NewMap[x, string, x, *x]()
m.Save("hi", x{})
}
// This will compile
func TestUnmarshalPointer(t *testing.T) {
m := NewMap[x, string, x, *x]()
m.GetTo("hi", &x{})
}
// This won't compile
func TestUnmarshalNoPointer(t *testing.T) {
m := NewMap[x, string, x, *x]()
m.GetTo("hi", x{})
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/369739.html
