不能将 'func(c Container) interface{} { return &MyService{} }' (type func(c Container) interface{}) 用作 ContainerFunc 类型

Cannot use 'func(c Container) interface{} { return &MyService{} }' (type func(c Container) interface{}) as type ContainerFunc

我正在尝试了解如何构建服务容器。虽然这不是一个推荐的过程,但我还是想从中学到一些东西。

但是在像下图这样构造代码之后。

我收到如下错误消息。

源代码:

    package unit

    import (
        "testing"
        "github.com/stretchr/testify/assert"
        framework "../../framework"
    )
    type ContainerFunc func(container Container) interface{}

    type MyService struct {
        Name string
    }

    type Container framework.Container

    func TestContainerSingleton(t *testing.T) {

        c := framework.New()

        assert.False(t, c.Has("test.service.name"))

        assert.Equal(t, []string{}, c.GetKeys())

        c.Set("my.service", func(c Container) interface{} {
            return &MyService{}
        })

    }

container.go

package framework

import (
    "fmt"
    "log"
    "reflect"
    "sync"
)

// Container is for containing any services
type Container interface {
    Set(name string, f ContainerFunc)
    Has(name string) bool
    Get(name string) interface{}
    GetKeys() []string
    Fill(name string, ds interface{})
    Extend(name string, f ExtenderFunc)
}

// ContainerFunc func will generate interfaces based on need
type ContainerFunc func(container Container) interface{}

// ExtenderFunc means interface
type ExtenderFunc interface{}

type container struct {
    values   map[string]ContainerFunc
    extends  map[string][]reflect.Value
    services map[string]interface{}
    mtx      *sync.RWMutex
}

//New method initialize a new Container and returns it.
func New() Container {
    return &container{
        services: make(map[string]interface{}),
        values:   make(map[string]ContainerFunc),
        extends:  make(map[string][]reflect.Value),
        mtx:      &sync.RWMutex{},
    }
}

/*
In Set method storing the container
*/
func (c *container) Set(name string, f ContainerFunc) {
    c.mtx.Lock()
    defer c.mtx.Unlock()

    //Checking if the service is in the format, if service is there throw a panic
    if _, ok := c.services[name]; ok {
        log.Panic("Can not overwrite initialized service")
    }
    c.values[name] = f
    fmt.Printf("%s service has been registered", name)
}

/*
Has Checks if the name exists in map and return boolean value
it first locks the c.values for reading then checks and at last using
defer it release the lock
*/
func (c *container) Has(name string) bool {
    //applying read lock on value map
    c.mtx.RLock()
    //releasing lock after return call
    defer c.mtx.RUnlock()
    // Checking if the value exists or not, and put the boolean value into "ok" variable
    if _, ok := c.values[name]; ok {
        return true
    }

    return false
}

func (c *container) Get(name string) interface{} {
    //locks reading from c.values
    c.mtx.RLock()
    _, ok := c.values[name]
    //unlocking it after reading and put the boolean value into the ok variable
    c.mtx.RUnlock()
    //if its false panic a error
    if !ok {
        panic(fmt.Sprintf("The service does not exist: %s", name))
    }

    //if panic is not triggered
    //read lock services from reading
    c.mtx.RLock()
    //check if the name is in the services
    _, ok = c.services[name]
    //read unlock the service map
    c.mtx.RUnlock()

    // the ok (boolean) is false type define container as c in "v" variable
    if !ok {
        v := c.values[name](c)

        c.mtx.RLock()
        c.services[name] = v
        c.mtx.RUnlock()
        // it itterates through the extends map and ....
        if extends, ok := c.extends[name]; ok {
            for _, extend := range extends {
                //creating an slice of reflect value
                result := extend.Call([]reflect.Value{reflect.ValueOf(v), reflect.ValueOf(c)})
                c.mtx.Lock()
                c.services[name] = result[0].Interface()
                c.mtx.Unlock()
            }
        }
    }

    c.mtx.RLock()
    defer c.mtx.RUnlock()
    return c.services[name]
}

// Fill Returns error if anything happens
func (c *container) Fill(name string, dst interface{}) {
    // getting the struct
    obj := c.Get(name)
    // added element the dst interface using fill funciton
    if err := fill(obj, dst); err != nil {
        log.Panic(err)
    }
}

//Extend mainly have control over the c.extends , it is appending a callback function
func (c *container) Extend(name string, f ExtenderFunc) {
    c.mtx.Lock()
    defer c.mtx.Unlock()

    if _, ok := c.services[name]; ok {
        log.Panic("Cannnot extend initialized service")
    }

    if _, ok := c.values[name]; !ok {
        log.Panicf("Cannot extend %s service", name)
    }

    c.extends[name] = append(c.extends[name], reflect.ValueOf(f))
}

// Get keys mainly creates a empty map , fill the map with all the value with string
//by appending and return the map
func (c *container) GetKeys() []string {
    c.mtx.RLock()
    defer c.mtx.RUnlock()

    keys := make([]string, 0)

    for k := range c.values {
        keys = append(keys, k)
    }
    return keys
}

//fill method just add an element to the dest interface (which is being injected)
func fill(src, dest interface{}) (err error) {
    defer func() {
        if r := recover(); r != nil {
            d := reflect.TypeOf(dest)
            s := reflect.TypeOf(src)
            err = fmt.Errorf("The fill destination should be a pointer to a %s , but you used a %s", s, d)
        }
    }()
    reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src))
    return err
}

我收到的错误消息,知道如何解决这个问题吗?:

Cannot use 'func(c Container) interface{} { return &MyService{} }' (type func(c Container) interface{}) as type ContainerFunc

如果我尝试通过根据猜测构建我自己的 Framework 来重建您的情况(使用 Go 1.13)——如果您向我们展示 Framework 中的内容将会有所帮助——我能得到的最接近的这是:

./unit.go:25:22: cannot use func literal (type func(Container) interface {})
as type framework.ContainerFunc in argument to c.Set

这是由于这一行:

type Container framework.Container

将其更改为:

type Container = framework.Container

因此这是现有类型的 别名 使代码构建。 (最好只在适当的地方使用 framework.Container,而不是定义您自己的 unit.Container 类型。)

(如果您的 IDE 从 framework.Container 中删除了 framework. 前缀,并且在这里缩短了 Go 编译器的错误消息,那就可以解释了。)