代码之家  ›  专栏  ›  技术社区  ›  Moonlit

在Golang中将`func()Foo`转换为`func)any`?

  •  -1
  • Moonlit  · 技术社区  · 5 月前

    问题

    当前的问题是,类型的函数 func() Foo 无法分配 func() any 在Golang。也许这是一个XY问题,所以我会解释为什么我会处于这种情况。

    例子

    我基本上有一个健康检查包(为了简单起见,这是一个简化的模型):

    //package: internal/health
    type Check struct {
        Name  string
        Func func() (metadata any, err error)
    }
    
    type Manager struct {
        checks []Check
    }
    
    func (m *Manager) RegisterCheck(check Check) {
        m.checks = append(m.checks , check)
    }
    
    func (m *Manager) PrintHealth() {
        for _, check := m.checks {
            output, _ := check.Func()
            slog.Info("Health", slog.Any("output", output))
            // In the actual implementation, I aggregate the checks and JSONify them
        }
    }
    

    然后,也许我有另一个包,它有一个我想添加到检查中的方法:

    //package: internal/service
    type Foo struct {}
    
    func (f Foo) Health() (string, error) {
        return "baz", nil
    }
    
    type Bar struct {}
    
    func (b Bar) Health() (map[string]int, error) {
        return map[string]int{"qux": 1} , nil
    }
    
    //package: cmd/app
    func main() {
        foo := service.Foo{}
        bar := service.Bar{}
    
        h := health.Manager{}
        h.RegisterCheck(health.Check{
            Name: "Foo",
            Func: foo.Health, // This is where the type error occurs
        })
        h.RegisterCheck(health.Check{
            Name: "Bar",
            Func: bar.Health, // This is where the type error occurs
        })
    }
    

    我试过/考虑过什么?

    • 将类型参数添加到 Manager Check
      • 问题? 经理 只能添加某种类型的检查,这意味着 Foo Bar 无法添加到同一个 经理 ,这基本上由整个应用程序共享。
    • 将类型参数添加到 RegisterCheck 检查
      • 问题?Golang不支持方法的类型参数。
    1 回复  |  直到 5 月前
        1
  •  1
  •   Burak Serdar    5 月前

    最简单的解决方案是定义Health函数以符合接口签名:

    func (f Foo) Health() (any, error) {
        return "baz", nil
    }
    
    func (b Bar) Health() (any, error) {
        return map[string]int{"qux": 1} , nil
    }
    

    如果目的只是记录返回值,那么这应该是可行的。

    如果你想保留返回类型,那么下一个选择是使用适配器:

      h.RegisterCheck(health.Check{
            Name: "Foo",
            Func: func() (any,error) {
                return foo.Health()
            },
        })
        h.RegisterCheck(health.Check{
            Name: "Bar",
            Func: func() (any,error) {
                return bar.Health()
            },
        })