簡體   English   中英

如何使用指針接收器方法和非指針接收器方法定義泛型類型

[英]How to define a generic type with a pointer receiver method and a non-pointer receiver method

我已經開始嘗試 Go generics。 有沒有辦法定義一個泛型類型,例如:一個方法不需要用指針接收器調用,另一種方法需要用指針接收器調用。

例子:

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)

好的,所以自我回答我的問題。 我還沒有找到一種方法來約束一個接口具有指針方法和非指針方法。

我不得不拆分接口(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{})
}

一如既往地感謝stackoverflow的友善。 希望這不會被否決票淹沒,並且有人會發現它有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM