不能将 '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 编译器的错误消息,那就可以解释了。)
我正在尝试了解如何构建服务容器。虽然这不是一个推荐的过程,但我还是想从中学到一些东西。
但是在像下图这样构造代码之后。
我收到如下错误消息。
源代码:
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 编译器的错误消息,那就可以解释了。)