Go语言 无法将“func(c Container)interface{} { return &MyService{} }”(类型func(c Container)interface{})用作类型ContainerFunc

mrfwxfqh  于 5个月前  发布在  Go
关注(0)|答案(1)|浏览(30)

我试图了解如何构建一个服务容器去。虽然这不是一个推荐的过程,但我想从中学到一些东西。
但是在构造了像下面这张图片这样的代码之后。
x1c 0d1x的数据
我得到一个错误消息如下.

源代码:

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 iterates over 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
}


我得到的错误消息,任何想法如何解决这个问题?:
无法将“func(c Container)interface{} { return &MyService{} }”(类型func(c Container)interface{})用作类型ContainerFunc

iqjalb3h

iqjalb3h1#

如果我试图通过猜测构建我自己的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类型。)
(If您的IDE正在从framework.Container删除framework.前缀,否则将缩短Go编译器的错误消息,这将解释它。

相关问题