我正在尝试将指向结构的指针分配给相同类型的已初始化结构指针的值。
做一个简单的服务定位器
代码是这样的
package main
import (
"fmt"
"reflect"
)
type Concrete struct {}
func (c *Concrete) Do(){}
type Doer interface {
Do()
}
func main() {
l := ServiceLocator{}
l.Register(&Concrete{})
var x Doer
if l.Get(&x); x!= nil {
fmt.Println("by interface pointer ok")
}
// This is not possible in my understanding
//var z Doer
//if l.Get(z); z!= nil {
// fmt.Println("by interface ok")
//}
var y *Concrete
if l.Get(y); y!= nil {
fmt.Println("by struct pointer ok")
}
}
type ServiceLocator struct {
services []interface{}
types []reflect.Type
values []reflect.Value
}
func (s *ServiceLocator) Register(some interface{}) {
s.services = append(s.services, some)
s.types = append(s.types, reflect.TypeOf(some))
s.values = append(s.values, reflect.ValueOf(some))
}
func (s *ServiceLocator) Get(some interface{}) interface{} {
k := reflect.TypeOf(some).Elem()
kind := reflect.TypeOf(some).Elem().Kind()
for i, t := range s.types {
if kind==reflect.Interface && t.Implements(k) {
reflect.Indirect(
reflect.ValueOf(some),
).Set(s.values[i])
} else if kind==reflect.Struct && k.AssignableTo(t.Elem()) {
fmt.Println(reflect.ValueOf(some).Elem().CanAddr())
fmt.Println(reflect.ValueOf(some).Elem().CanSet())
fmt.Println(reflect.Indirect(reflect.ValueOf(some)))
reflect.ValueOf(some).Set(s.values[i])
}
}
return nil
}
Run Code Online (Sandbox Code Playgroud)
尽管我尝试过,但我不断收到运行时错误,例如
panic: reflect: reflect.Value.Set using unaddressable value
Run Code Online (Sandbox Code Playgroud)
试玩这里
需要帮助,非常感谢!
在 JimB 的帮助下,这里的信息是固定播放https://play.golang.org/p/_g2AbX0yHV
您不能将指针的值直接分配给y,因为您传递的是yinto的值Get,而不是其地址。您可以传入y(type **Concrete)的地址,以便您可以将指针 ( *Concrete)分配给y。如果直接分配值是安全的,则将已注册指针的间接分配给y,但y必须使用有效值进行初始化,以便有地址可写入。
n := 42
p := &n
x := new(int)
// set the value to *x, but x must be initialized
reflect.ValueOf(x).Elem().Set(reflect.ValueOf(p).Elem())
fmt.Println("*x:", *x)
var y *int
// to set the value of y directly, requires y be addressable
reflect.ValueOf(&y).Elem().Set(reflect.ValueOf(p))
fmt.Println("*y:", *y)
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/6tFitP4_jt