【发布时间】:2021-01-19 06:27:41
【问题描述】:
我想在程序的任何阶段对给定包中定义的结构的所有实例执行操作。为了做到这一点,我已经考虑开发一个收集这些实例的函数。但我还没有找到任何东西。
为了阐明我的目标(遵循“@Muffin Top”和“@Volker”的回答),我目前手动将此注册到每个包中存在的指针存储中。这种方法有两个问题,注册是一项普通的任务,而且容易出错。
为了说明我的情况,考虑一个包foo 和一个结构Foo。 Foo 有一个string 字段Name。该包还定义了Foo 的两个实例,声明为Foo1 和Foo2
package foo
type Foo struct {
Name string
}
var Foo1, Foo2 = Foo{Name: "Foo1"}, Foo{Name: "Foo2"}
我正在尝试实现的GetInstancesOfPkg 将被调用,如下例所示。要执行的操作只是打印Name 字段。
这是一个工作示例,但带有 GetInstancesOfPkg 的模型版本。
package main
import (
"log"
"reflect"
"github.com/thomaspeugeot/test-heapdump/foo"
)
func main() {
s := GetInstancesOfPkg("github.com/thomaspeugeot/test-heapdump/foo")
for _, instance := range s {
// cast instance on foo.Foo
if f, ok := instance.(*foo.Foo); !ok {
log.Panic("Unknown Struct " + reflect.TypeOf(instance).Name())
} else {
log.Printf("Instance of Foo has name %s ", f.Name)
}
}
}
// GetInstancesOfPkg return a slice of instances of Struct defined in the package pkgPath
// --- this is the mockup verion ---
func GetInstancesOfPkg(pkgPath string) (interfaceSlice []interface{}) {
var listOfFooInstances = []*foo.Foo{&foo.Foo1, &foo.Foo2}
interfaceSlice = make([]interface{}, len(listOfFooInstances))
for i, d := range listOfFooInstances {
interfaceSlice[i] = d
}
return
}
对于解决方案,我知道reflect 标准库或我知道的任何其他库中没有这样的功能。但是,我正在考虑:
-
一种解析整个程序内存、识别每个变量、获取其类型并收集与包的结构类型匹配的算法的算法。由于 delve 和 heapdump 确实解析了整个内存并且 delve 可以猜测变量类型,所以我有一种预感,我想要的功能可以实现。我一直在尝试了解 delve 的工作情况或 heapcoredump 的开发方式,但对于预期的目标来说,这是一个太大的知识。
-
另一种方法是添加一个预编译步骤,通过在每次变量初始化时添加注册来修改抽象语法树 (AST)。
-
我什至不确定 go 是否可以实现这种级别的反射(或者它是否可移植?)
-
性能不是问题,可以使用必要的 wathever 标志编译程序,或者可以解析整个内存。
【问题讨论】:
-
Go 标准库不提供枚举给定类型值的方法。你试图解决的更高层次的问题是什么?可能有办法编写一些应用程序代码来解决这个问题。
-
这个更高级别的问题是,目前,我在 pkg 存储中手动注册所有实例
-
请注意,即使是垃圾收集器也可能永远看不到某些类型的某些实例。只有编译器自己知道。就可移植性和可靠性而言,您使用预编译步骤的想法是最有希望的。
-
@torek,感谢您对 GC 的见解。我将尝试预编译步骤,看到生成的代码会很有趣。
标签: go reflection garbage-collection delve