[英]golang how to access promoted type
我在两个特定结构中提升了一个“通用”结构。 例如:
type common struct {
name string
}
type apple struct {
common
}
type orange struct {
common
}
省略了特定于apple
和orange
的细节。
我有一个特定于类型的 map ,例如map[string]*apple
和map[string]*orange
。
我正在尝试制作一个可以提取common
指针的 function。 从我到目前为止的尝试来看,似乎需要反思。
我的 function 是:
func getFruitArray(theMap interface{}) []*common {
m := reflect.ValueOf(theMap)
cf := make([]*common, 0, m.Len())
for _, mk := range m.MapKeys() {
v := m.MapIndex(mk)
cf = append(cf, v.Interface().(*common))
}
return cf
}
这个 function 在cf = append(cf, v.Interface().(*common))
处失败:
panic: interface conversion: interface {} is *main.apple, not *main.common
有没有办法在这个 function 中访问提升的 struct common
而无需专门引用apple
或orange
?
请参阅 Burak 的回答,它做出了必须调用方法来接收值的合理妥协。
无论如何,下面是一个按照您的计划使用反射的解决方案。 请注意, common
需要是Common
(导出字段),否则反映 package 无法读取它。
package main
import (
"log"
"reflect"
)
type Common struct {
name string
}
type apple struct {
Common
}
type orange struct {
Common
}
func getFruitArray(theMap interface{}) []*Common {
m := reflect.ValueOf(theMap)
cf := make([]*Common, 0, m.Len())
for _, mk := range m.MapKeys() {
v := m.MapIndex(mk)
f := v.Elem().FieldByName("Common")
cf = append(cf, f.Addr().Interface().(*Common))
}
return cf
}
func main() {
appleMap := make(map[string]*apple)
orangeMap := make(map[string]*orange)
a1 := &apple{}
a1.name = "my apple"
appleMap["test"] = a1
o1 := &orange{}
o1.name = "my orange"
orangeMap["test2"] = o1
f1 := getFruitArray(appleMap)
for _, c := range f1 {
log.Printf("f1: %s", c.name)
}
f2 := getFruitArray(orangeMap)
for _, c := range f2 {
log.Printf("f2: %s", c.name)
}
}
你不需要反思。 一种方法是使用接口:
type common struct {
name string
tag string
}
func (c *common) GetCommon() *common {return c}
type WithCommon interface {
GetCommon() *common
}
然后你可以这样做:
func getFruitArray(theMap map[string]WithCommon) []*common {
cf := make([]*common, 0, theMap.Len())
for _,k:=range theMap {
cf=append(cf,k.GetCommon())
}
return cf
}
但你还必须这样做:
appleMap := make(map[string]WithCommon)
orangeMap := make(map[string]WithCommon)
如果您知道自己在做什么,则可以使用unsafe
的 package。 但如果你不这样做,那就不要。
func getFruitArray(theMap interface{}) []*common {
m := reflect.ValueOf(theMap)
cf := make([]*common, 0, m.Len())
for _, mk := range m.MapKeys() {
v := m.MapIndex(mk).Elem() // use elem to dereference the pointer
t := v.Type()
// If you know that common is always the first field
// then you can just use v.Field(0). But if common's
// position is not guaranteed then use a loop like below.
for i := 0; i < v.NumField(); i++ {
sf := t.Field(i)
if sf.Anonymous && sf.Name == "common" {
f := v.Field(i)
// 1. get the address of the common field
// 2. convert it first to unsafe.Pointer
// 3. then convert it to *common
c := (*common)(unsafe.Pointer(f.UnsafeAddr()))
cf = append(cf, c)
}
}
}
return cf
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.