如何将A和B的选定值注入以下儿童C?
decoder.go (Playground link)
package main
import (
"fmt"
)
type Input struct {
A []A
}
type A struct {
AID int
B []B
}
type B struct {
BID int
C []C
}
type C struct {
// I want to inject only AID and BID here
// But, without injecting A and B directly
// (without recursively)
CID int
}
func main() {
res := Input{
A: []A {
A {
AID: 1,
B: []B {
B{ BID: 11, C: []C{{ 111 }, { 111 }}},
B{ BID: 12, C: []C{{ 121 }, { 122 }}},
},
},
A {
AID: 2,
B: []B {
B{ BID: 21, C: []C{{ 211 }, { 211 }}},
B{ BID: 22, C: []C{{ 221 }, { 222 }}},
},
},
},
}
// I want to inject AID and BID into C
// WITHOUT nested loops like this:
for _, a := range res.A {
for _, b := range a.B {
for _, c := range b.C {
fmt.Println(a.AID, b.BID, c.CID)
}
}
}
}
答案 0 :(得分:1)
如果您不想使用嵌套循环,则一种解决方案是使用递归调用和反射将属性/属性注入到结构中。在以下实现中,要注入的属性/属性包含在结构实现Injectable
接口中。可以在Go Playground找到工作示例。
定义界面。
type Injectable interface {
InjectTo(v interface{})
}
定义包含要注入的属性/属性的数据结构,例如
type Property struct {
AID int
BID int
}
type C struct {
// The properties will be injected here
Property
CID int
}
使用反射和递归调用实现InjectTo
。
//Method must be pointer receiver since p will be used
//as temporary placeholder for parent properties/attributes.
func (p *Property) injectRecursive(v reflect.Value, it reflect.Type, pv reflect.Value) {
switch v.Kind() {
case reflect.Struct:
vt := v.Type()
//Embedded struct is a 'value' type implement Injectable
if vt.Implements(it) {
//Inject value to embedded struct
ot := pv.Type()
for k := 0; k < pv.NumField(); k++ {
name := ot.Field(k).Name
f := v.FieldByName(name)
if f.CanSet() {
f.Set(pv.Field(k))
}
}
} else {
for k := 0; k < v.NumField(); k++ {
fv := v.Field(k)
//Match by field name.
//For more robust and generic solution
//consider using other approach, e.g. tag
f := pv.FieldByName(vt.Field(k).Name)
if f.CanSet() {
f.Set(fv)
} else {
p.injectRecursive(fv, it, pv)
}
}
}
case reflect.Slice, reflect.Array:
for k := 0; k < v.Len(); k++ {
p.injectRecursive(v.Index(k), it, pv)
}
case reflect.Ptr:
if v.IsValid() {
p.injectRecursive(v.Elem(), it, pv)
}
}
}
//InjectTo must be Value (not pointer) receiver
func (p Property) InjectTo(s interface{}) {
sv := reflect.Indirect(reflect.ValueOf(s))
pv := reflect.Indirect(reflect.ValueOf(&p))
it := reflect.TypeOf((*Injectable)(nil)).Elem()
p.injectRecursive(sv, it, pv)
}
您可以通过以下方式注入属性:
res := Input{...}
prop := Property{}
prop.InjectTo(&res)
答案 1 :(得分:0)
Go通常鼓励使用显式方法,并且嵌套for循环在这里实际发生的事情上是非常明确的。可能没有必要尝试找到更简洁的解决方案,Go可能不会提供它。