Go - Force interface to be satisfied only by types with pointer receivers on methods?

PHPz
Release: 2024-02-10 09:27:20
forward
1192 people have browsed it

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

php editor Baicao introduces to you the mandatory interface rules in Go language, that is, only types with pointer receivers on methods can meet the requirements of the interface. Go language is a statically typed programming language that implements polymorphism through interfaces. When defining an interface, you can specify the receiver type of a method, which can be a value type or a pointer type. However, when we use mandatory interface rules, only types with pointer receivers on methods can meet the requirements of the interface. This is because pointer types can modify the content of the value, but value types cannot. This rule ensures that interface methods do not cause unpredictable behavior when manipulating values. By understanding this rule, we can better understand the use and design of interfaces in the Go language.

Question content

I'm doing some experiments with type parameters to come up with a general way of concatenating structures to generate responses to json http requests.

The method interface that the structure must implement has a setparams method. As long as the implementation uses pointer receivers, this will work as expected.

My question: If setparams has a value receiver, is there any way to make it a compile-time error?

The following example demonstrates the problem with setparams with a value receiver:

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)
}
Copy after login

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

Solution

You can't do this.

When you do the following in your code:

var m T = new(M)
Copy after login

Even though the type set of t only includes *m as type items, the method set of *m is also included on m Declared method. The compiler cannot check how this method appears in *m's method set.

When declaring a method setparam on badping, it is your responsibility to ensure that the method does not attempt in vain to modify the receiver.

The above is the detailed content of Go - Force interface to be satisfied only by types with pointer receivers on methods?. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template