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

标签 reflection go

我需要向 log15 记录器添加属性,但如果我不小心添加了两次,它将出现两次。因此,我想添加逻辑以查看该属性是否已填充,如果已填充则跳过该操作。

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

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

我如何访问“ctx”字段并在我的值已经存在时进行验证?我已经尝试了一些反射技巧并且可以获取数据类型,但我不知道如何获取值。

最佳答案

我将首先详细了解您的要求,即访问存储在记录器上下文中的属性。

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

永远不要那样做

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

如果您不想在记录器中有两次相同的属性,请不要一开始就把它放两次,这比维护上面的代码要好得多,也容易得多。

如果您对此仍然不够信任自己,那么请将记录器包装在一个结构中,您可以在该结构中存储记录器中包含的属性。至少这将是您亲手操作的东西,并且做同样的工作。

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

关于reflection - golang - 如何访问结构的内部结构(反射?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37493805/

相关文章:

c# - 反射如何检索分配给变量的数据?

java - 当传递枚举的字符串值时,如何在运行时访问任何已知枚举的值?

java - 确保通用 lambda 表达式的类型安全

go - 如何用golang实现slowEqual

api - golang 缺少 len 参数

compilation - 在 Go 中构建和引用我自己的本地包

java - 如何使用java反射过滤方法

java - Class API 中的 getDeclaredConstructors 和 getConstructors 有什么区别?

go - 如何在 Go 中重用原始的 strings.Reader?

c - 尝试扩展 golang Pigpio 包装函数 gpioWaveAddGeneric