Maison  >  Article  >  développement back-end  >  Go - Forcer l'interface à être satisfaite uniquement par les types avec des récepteurs de pointeurs sur les méthodes ?

Go - Forcer l'interface à être satisfaite uniquement par les types avec des récepteurs de pointeurs sur les méthodes ?

PHPz
PHPzavant
2024-02-10 09:27:201167parcourir

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

l'éditeur php Baicao vous présente les règles d'interface obligatoires en langage Go, c'est-à-dire que seuls les types avec des récepteurs de pointeurs sur les méthodes peuvent répondre aux exigences de l'interface. Le langage Go est un langage de programmation typé statiquement qui implémente le polymorphisme via des interfaces. Lors de la définition d'une interface, vous pouvez spécifier le type de récepteur d'une méthode, qui peut être un type valeur ou un type pointeur. Cependant, lorsque nous utilisons des règles d'interface obligatoires, seuls les types avec des récepteurs de pointeurs sur les méthodes peuvent répondre aux exigences de l'interface. En effet, les types pointeurs peuvent modifier le contenu de la valeur, mais pas les types valeur. Cette règle garantit que les méthodes d'interface ne provoquent pas de comportement imprévisible lors de la manipulation des valeurs. En comprenant cette règle, nous pouvons mieux comprendre l’utilisation et la conception des interfaces dans le langage Go.

Contenu de la question

Je fais quelques expériences avec les paramètres de type pour trouver une manière générale de concaténer des structures pour générer des réponses aux requêtes http json.

Méthodes que la method 接口有一个 setparams structure doit mettre en œuvre. Tant que l'implémentation utilise des récepteurs de pointeurs, cela fonctionnera comme prévu.

Ma question : si setparams a un récepteur de valeur, existe-t-il un moyen d'en faire une erreur de compilation ?

L'exemple suivant illustre le problème de setparams avec un récepteur de valeur :

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)
}

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

Workaround

Vous ne pouvez pas faire ça.

Lorsque vous effectuez ce qui suit dans votre code :

var m T = new(M)

Mêmet的类型集仅包括*m作为类型项,*m的方法集也包括在m上声明的方法。编译器无法检查该方法如何出现在 *m la méthode est ciblée.

Chez badping 上声明方法 setparam il est de votre responsabilité de vous assurer que la méthode ne tente pas en vain de modifier le récepteur.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer