go - Cannot use 'func(c Container) interface{} { return &MyService{} }' (type func(c Container) interface{}) as type ContainerFunc
问题描述
I'm trying to understand how to build a service container to go. Though it's not a recommended process still I want to learn something from it.
But after structuring code like this image below.
I'm getting an error message like this below.
Source code:
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
}
the error message I'm getting, Any idea how to solve this?:
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.
前缀framework.Container
,或者在此处缩短 Go 编译器的错误消息,那就可以解释了。)
推荐阅读
- java - java stream().filter() 的最佳实践
- jquery - 带图像的引导时间轴
- ansible - ansible 是否允许基于主机的变量语法?
- verilog - Verilog 不计算线值
- rust-cargo - 关于 Cargo.toml 依赖项中的 toml 换行符
- jquery - 用于日历的 jQuery UI 可拖放和可拖动
- emulation - 6502 个指令时钟周期背后的逻辑是什么?
- androidx - 替换已弃用的 BrowseFragment AndroidTV
- python - 根据另一列的掩码修改 Pandas 数据框列的符号?
- ios - 我试图让输入的数据进行计算并显示在标签中