Golang,带有指针和接口的用例

Golang,带有指针和接口的用例

问题描述:

I am writing a library I'll need to use in others parts of my programs, for this I had to use a lot interfaces and I ended up in a case I don't know how to solve.

Here is my code :

main.go

package main

import (
    "test/bar"
)

// Foo is defined in another package
type Foo struct {
    WhatWeWant string
}

func (f *Foo) getResult() interface{} {
    return f.WhatWeWant
}

func newFoo() interface{} {
    return &Foo{
        WhatWeWant: "test",
    }
}

func main() {
    bar := bar.Bar{
        NewFooer: newFoo,
    }
    bar.Execute()
}

bar/bar.go

package bar

import (
    "fmt"
    "reflect"
)

type myInterface interface {
    getResult() interface{}
}

type Bar struct {
    NewFooer func() interface{}
}

func (b *Bar) Execute() {
    foo := b.NewFooer()

    // executeLib only accept pointer
    executeLibWrapper(foo)

    whatWeWant := foo.(myInterface).getResult()
    fmt.Println(whatWeWant)
    fmt.Println("Win!")

}

// This function is executed in an external library I have no control on
func executeLibWrapper(src interface{}) {
    executeLib(reflect.TypeOf(src))
}

func executeLib(src reflect.Type) {

    if src.Kind() == reflect.Ptr {
        executeLib(src.Elem())
        return
    }

    switch src.Kind() {
    case reflect.Struct:
        fmt.Println("Struct OK!")
    default:
        panic(fmt.Sprintf("Can't detect struct, we detect %s", src.Kind()))
    }
}

I get the error

panic: interface conversion: *main.Foo is not bar.myInterface: missing method getResult

My goal is to be able to call getResult() after executing the library. Here is a playground : https://play.golang.org/p/7G2wc6uGngH. This playground works, so there is a strong possibilities that the problem come from the fact it is in different packages.

Note that I need to pass a pointer to executeLib, I can't get the pointer in execute() because otherwise I'll lose the foo type and can't execute the library : https://play.golang.org/p/A8ETfuMQyQB. This is why I have to return the pointer in newFoo()

Thank you for your help !

If you want to share an interface and their funcs across packages you have export the interface and its funcs:

type MyInterface interface {
    GetResult() interface{}
}

When you change the implementation of Foo

func (f *Foo) GetResult() interface{} {
    return f.WhatWeWant
}

and the call

whatWeWant := foo.(MyInterface).GetResult()

it compiles and executes without panic.

Got the result here. Hope this can help.

Seems the trick is using these. Adding these snippet introduces the smallest impact on code.

Just make NewFooer a member function of Bar. When NewFooer is invoked newFoo is called.

func (m *Bar) NewFooer() interface{} {
    return newFoo()
}

Eventually this snippet is invoked as well

func newFoo() interface{} {
    return &Foo{
        WhatWeWant: "test",
    }
}