繁体   English   中英

golang如何访问提升类型

[英]golang how to access promoted type

我在两个特定结构中提升了一个“通用”结构。 例如:

type common struct {
    name string
}

type apple struct {
    common
}

type orange struct {
    common
}

省略了特定于appleorange的细节。

我有一个特定于类型的 map ,例如map[string]*applemap[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而无需专门引用appleorange

游乐场示例

请参阅 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)
    }
}

https://go.dev/play/p/FrkRnu_G2Xd

你不需要反思。 一种方法是使用接口:

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
}

https://go.dev/play/p/XMi86jj2wiW

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM