golang - 如何访问struct的内部结构(反射?)

时间:2016-05-27 23:49:51

标签: reflection go

我需要为log15记录器添加属性,但如果我无意中添加了两次,它将出现两次。所以,我想添加逻辑以查看属性是否已填充,如果是,则跳过操作。

这是我输出日志对象时得到的结果:

log="&{ctx:[field1 val1 field2 val2 field3 val3 field2 val2] h:0xc82052c1e0}"

如何访问该“ctx”字段并验证我的值何时已存在?我尝试了一些反射技巧并且可以获得数据类型,但我无法弄清楚如何获得该值。

1 个答案:

答案 0 :(得分:1)

我将首先完成您所要求的内容,即访问存储在记录器上下文中的属性。

Go中的反思基于TypeValue。您无法使用Type访问任何数据,您只需拥有该类型的信息(惊喜!)。所以,在这里你必须使用反射的Value方。

但是,问题是记录器的ctx字段未导出,因此无法直接访问它。但是,使用一些不安全的操作可以使它成为可能。

以下是代码:

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

type logger struct {
    ctx []interface{}
}

type Logger interface {
    Populate(ctx ...interface{})
}

func NewLogger() Logger {
     return &logger{}
}

func (l *logger) Populate(ctx ...interface{}) {
    l.ctx = ctx
}

func main() {
    log := NewLogger()
    log.Populate(42, "42", 84, "84")
    fmt.Println(log)
    // &{[42 42 84 84]}
    v := reflect.ValueOf(log).Elem()
    field := v.FieldByName("ctx")
    ar := *(*[]interface{})(unsafe.Pointer(field.UnsafeAddr()))

    for _, i := range ar {
        fmt.Println(i)
    }
    // 42 42 84 84
}

Go playground

永远不要这样做

代码有效,并产生您的期望。但是,您正在使用反射和不安全操作从第三方库的未导出结构中获取值。我的英语不够好,无法正确表达糟糕这是怎么回事。

如果您不希望在记录器中具有两倍相同的属性,请不要将它放在第一位,这比维护上面的代码要好得多,容易得多。

如果您仍然不相信自己,请将记录器包装在存储记录器中包含的属性的结构中。至少它会是你掌握的东西,并做同样的工作。

因此,您可以自由使用此代码。但是如果你想帮自己一个忙,那么你就不会在那种情况下使用它。