【问题标题】:Handling interface implementation panics not detected on compile time处理编译时未检测到的接口实现恐慌
【发布时间】:2021-10-06 06:02:12
【问题描述】:

当客户端结构嵌入接口时,即使提供的结构没有“实现”接口,代码也能正常编译。

以下面 2 秒后发生恐慌并恢复的例子来说明问题:

service.go

package service

import (
    "fmt"
)

type (
    Service struct {
        clients []Client
    }
    Client interface {
        Valid() bool
        Run()
    }
)

func (s *Service) AddClient(client Client) {
    defer func() {
        if e := recover(); e != nil {
            fmt.Println("recovered: ", e)
        }
    }()
    // Question:
    // Instead of panic here let client know that
    // their CustomClient is missing Valid implementation
    //
    // fmt.Printf("%T does not implement Client (missing Valid method)\n", client)
    // return
    if !client.Valid() {
        return
    }
    s.clients = append(s.clients, client)
}

// Run expects that
func (s *Service) Run() {
    fmt.Println("Service Run")
    if len(s.clients) > 0 {
        for _, client := range s.clients {
            client.Run()
            fmt.Println("Client Run")
        }
    } else {
        fmt.Println("Service Invalid")
    }
}


example_invalidclient_test.go想让这个测试通过

package service_test

import (
    "fmt"
    "service"
    "time"
)

type CustomClient struct {
    service.Client
}

func (c *CustomClient) Run() {
    fmt.Println("CustomClient run")
}

func ExampleInvalidClient() {
    time.Sleep(2 * time.Second)
    c := &service.Service{}
    c.AddClient(&CustomClient{})

    c.Run()
    // Output:
    // *service_test.CustomClient does not implement Client (missing Valid method)
    // Service Run
    // Service Invalid
}

go test .

--- FAIL: ExampleInvalidClient (2.00s)
got:
recovered:  runtime error: invalid memory address or nil pointer dereference
Service Run
Service Invalid
want:
*service_test.CustomClient does not implement Client (missing Valid method)
Service Run
Service Invalid

是否可以在编译时检测到它,而不是进行自定义运行时验证并呈现编译错误,例如缺少实现错误。或者在恐慌恢复中获得更明确的恐慌原因而不是runtime error: invalid memory address or nil pointer dereference

例如更清晰的错误就像示例测试

*CustomClient does not implement Client (missing Valid method)

比寻找包代码(*Service).AddClient(...)做什么

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x497b3c]

goroutine 1 [running]:
main.(*Service).AddClient(...)

【问题讨论】:

标签: go


【解决方案1】:

正如所建议的,当服务 API 存在设计缺陷时可能会出现问题。 这是解决方案如何更改 API 设计以处理此类用例有什么问题。也许它可以帮助某人。

service.go

package service

import (
    "fmt"
)

type (
    Service struct {
        clients []*Client
    }
    Client struct {
        valid func() bool
    }
)

func (c *Client) Valid(fn func() bool) {
    c.valid = fn
}

func (*Client) run() {}

func NewClient() *Client {
    return &Client{}
}

func (s *Service) AddClient(client *Client) {
    if client.valid == nil {
        fmt.Printf("%T does not implement Client (missing Valid method)\n", client)
        return
    }
    s.clients = append(s.clients, client)
}

// Run expects that
func (s *Service) Run() {
    fmt.Println("Service Run")
    if len(s.clients) > 0 {
        for _, client := range s.clients {
            if client.valid() {
                client.run()
                fmt.Println("Client Run")
            }
        }
    } else {
        fmt.Println("Service Invalid")
    }
}

example_client_test.go

package service_test

import (
    "fmt"
    "service"
    "time"
)

type CustomClient struct{}

func (c *CustomClient) Run() {
    fmt.Println("CustomClient run")
}

func ExampleInvalidClient() {
    time.Sleep(2 * time.Second)
    s := &service.Service{}
    c := service.NewClient()

    s.AddClient(c)

    s.Run()
    // Output:
    // *service.Client does not implement Client (missing Valid method)
    // Service Run
    // Service Invalid
}

func ExampleValidClient() {
    time.Sleep(2 * time.Second)
    s := &service.Service{}
    c := service.NewClient()
    c.Valid(func() bool {
        return true
    })
    s.AddClient(c)

    s.Run()
    // Output:
    // Service Run
    // Client Run
}

【讨论】:

  • 为什么服务没有提供强制传递客户端的构造函数?
  • 实际服务可以有无限客户端
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-23
  • 2015-03-29
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-06
相关资源
最近更新 更多