Heim > Backend-Entwicklung > Golang > Go - Erzwingen, dass die Schnittstelle nur von Typen mit Zeigerempfängern auf Methoden erfüllt wird?

Go - Erzwingen, dass die Schnittstelle nur von Typen mit Zeigerempfängern auf Methoden erfüllt wird?

PHPz
Freigeben: 2024-02-10 09:27:20
nach vorne
1197 Leute haben es durchsucht

Go - 强制接口仅由方法上带有指针接收器的类型满足?

php-Editor Baicao stellt Ihnen die obligatorischen Schnittstellenregeln in der Go-Sprache vor, das heißt, nur Typen mit Zeigerempfängern auf Methoden können die Anforderungen der Schnittstelle erfüllen. Die Go-Sprache ist eine statisch typisierte Programmiersprache, die Polymorphismus über Schnittstellen implementiert. Beim Definieren einer Schnittstelle können Sie den Empfängertyp der Methode angeben, der ein Werttyp oder ein Zeigertyp sein kann. Wenn wir jedoch verbindliche Schnittstellenregeln verwenden, können nur Typen mit Zeigerempfängern auf Methoden die Anforderungen der Schnittstelle erfüllen. Dies liegt daran, dass Zeigertypen den Inhalt des Werts ändern können, Werttypen jedoch nicht. Diese Regel stellt sicher, dass Schnittstellenmethoden bei der Manipulation von Werten kein unvorhersehbares Verhalten verursachen. Wenn wir diese Regel verstehen, können wir die Verwendung und das Design von Schnittstellen in der Go-Sprache besser verstehen.

Frageninhalt

Ich experimentiere gerade mit Typparametern, um eine allgemeine Methode zum Verketten von Strukturen zu finden, um Antworten auf JSON-HTTP-Anfragen zu generieren.

Methoden, die die method 接口有一个 setparams Struktur implementieren muss. Solange die Implementierung Zeigerempfänger verwendet, funktioniert dies wie erwartet.

Meine Frage: Wenn setparams einen Wertempfänger hat, gibt es eine Möglichkeit, daraus einen Fehler bei der Kompilierung zu machen?

Das folgende Beispiel verdeutlicht das Problem von setparams mit einem Wertempfänger:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type PingParams struct {
    Name string
}

type PingResponse struct {
    Message string
}

func (p PingParams) Greeting() string {
    if p.Name != "" {
        return fmt.Sprintf("Hello, %s", p.Name)
    }

    return fmt.Sprintf("Hello, nobody!")
}

type GoodPing struct {
    Params PingParams
}

// SetParams has a pointer receiver.
func (m *GoodPing) SetParams(p PingParams) {
    fmt.Printf("assign %v with pointer receiver, Good!\n", p)
    m.Params = p
}
func (m GoodPing) Run() (*PingResponse, error) {
    return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}

type BadPing struct {
    Params PingParams
}

// SetParams has a value receiver.
func (m BadPing) SetParams(p PingParams) {
    fmt.Printf("assign %v with value receiver, Bad!\n", p)
    m.Params = p
}
func (m BadPing) Run() (*PingResponse, error) {
    return &PingResponse{Message: fmt.Sprintf("%T %s", m, m.Params.Greeting())}, nil
}

type Method[M, RQ, RS any] interface {
    // Run builds the RPC result.
    Run() (*RS, error)
    // SetParams is intended to set the request parameters in the struct implementing the RPC method.
    // This then allows the request parameters to be easily available to all methods of the Method struct.
    // The method MUST have a pointer receiver. This is NOT enforced at compile time.
    SetParams(p RQ)
    // The following line requires the implementing type is a pointer to M.
    *M
    // https://stackoverflow.com/a/72090807
}

func HandlerMethod[M, RQ, RS any, T Method[M, RQ, RS]](in json.RawMessage) (*RS, error) {
    // A real implementation of this would return a func for wiring into a request router

    var req RQ

    err := json.Unmarshal(in, &req)

    if err != nil {
        return nil, err
    }

    var m T = new(M)

    m.SetParams(req)

    return m.Run()
}

func main() {

    payload := []byte(`{"Name": "Mark"}`)

    bad, err := HandlerMethod[BadPing, PingParams, PingResponse](payload)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(bad.Message)

    good, err := HandlerMethod[GoodPing, PingParams, PingResponse](payload)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(good.Message)
}
Nach dem Login kopieren

https://go.dev/play/p/eii8adkmdxe

Problemumgehung

Das ist nicht möglich.

Wenn Sie in Ihrem Code Folgendes tun:

var m T = new(M)
Nach dem Login kopieren

Sogart的类型集仅包括*m作为类型项,*m的方法集也包括在m上声明的方法。编译器无法检查该方法如何出现在 *m die Methode ist fokussiert.

Bei badping 上声明方法 setparam liegt es in Ihrer Verantwortung sicherzustellen, dass die Methode nicht vergeblich versucht, den Empfänger zu verändern.

Das obige ist der detaillierte Inhalt vonGo - Erzwingen, dass die Schnittstelle nur von Typen mit Zeigerempfängern auf Methoden erfüllt wird?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage