当前位置: 首页 > 面试题库 >

如何在运行时发现所有包类型?

朱浩大
2023-03-14
问题内容

据我所知,反射包中没有类型发现机制,该机制希望您已经具有要检查的类型或值的实例。

还有 其他 方法可以发现正在运行的go包中的所有导出类型(尤其是结构)吗?

这是我希望拥有的(但不存在):

import "time"
import "fmt"

func main() {
    var types []reflect.Type
    types = reflect.DiscoverTypes(time)
    fmt.Println(types)
}

最终目标是能够发现满足特定条件的程序包的所有结构,然后能够实例化这些结构的新实例。

顺便说一句,识别类型的注册功能对于我的用例 不是 有效的方法。

无论您是否认为这是一个好主意,这就是为什么我想要这种功能(因为我知道您会问):

我编写了一个代码生成实用程序,该实用程序可以加载源文件并构建AST以扫描嵌入指定类型的类型。该实用程序的输出是一组基于发现类型的go测试功能。我使用此工具go generate来创建测试功能,然后运行go test以执行生成的测试功能。每次测试更改(或添加新类型)时,我都必须重新运行go
generate才能重新运行go test。这就是注册功能不是有效选项的原因。我想避免此go generate步骤,但这将需要我的实用程序成为正在运行的程序包导入的库。库代码需要以某种方式在扫描过程中扫描正在运行的名称空间,init()以查找嵌入预期库类型的类型。


问题答案:

(请参阅底部的2019更新)

警告 :未经测试且骇客。每当发布新版本的Go时可能会中断。

通过对Go的运行时进行一些修改,可以获得运行时知道的所有类型。在您自己的程序包中包含一个小的程序集文件,其中包含:

TEXT yourpackage·typelinks(SB), NOSPLIT, $0-0
    JMP reflect·typelinks(SB)

在中yourpackage,声明函数原型(无主体):

func typelinks() []*typeDefDummy

除了类型定义:

type typeDefDummy struct {
    _      uintptr           // padding
    _      uint64            // padding
    _      [3]uintptr        // padding
    StrPtr *string           
}

然后只需调用typelinks,html" target="_blank">遍历切片并读取每个StrPtr作为名称。寻找那些以开头的人yourpackage。请注意,如果有两个yourpackage在不同路径中调用的包,则此方法将不会明确工作。

我可以以某种方式挂接到反射包中以实例化这些名称的新实例吗?

是的,假设d是type的值*typeDefDummy(请注意星号,非常重要):

t := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&d)))

现在t是一个reflect.Type可以实例化reflect.Values的值。

编辑:我测试并成功执行了此代码,并已将其作为要点上传。

调整软件包名称,并根据需要添加路径。

更新2019

自从我最初发布此答案以来,发生了很多变化。这是对如何在2019年使用Go 1.11进行相同操作的简短描述。

$GOPATH/src/tl/tl.go

package tl

import (
    "unsafe"
)

func Typelinks() (sections []unsafe.Pointer, offset [][]int32) {
    return typelinks()
}

func typelinks() (sections []unsafe.Pointer, offset [][]int32)

func Add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
    return add(p, x, whySafe)
}

func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer

$GOPATH/src/tl/tl.s

TEXT tl·typelinks(SB), $0-0
    JMP reflect·typelinks(SB)

TEXT tl·add(SB), $0-0
    JMP reflect·add(SB)

main.go

package main

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

func main() {
    sections, offsets := tl.Typelinks()
    for i, base := range sections {
        for _, offset := range offsets[i] {
            typeAddr := tl.Add(base, uintptr(offset), "")
            typ := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&typeAddr)))
            fmt.Println(typ)
        }
    }
}


 类似资料:
  • 问题内容: 我有两个如下的Java类 没有包装: 在包装中: 我可以同时编译它们: 但是,我只能运行第一个: 我该如何跑步? 问题答案: 如果将 源 放在与包名称()相匹配的适当目录层次结构中,并从层次结构的根目录()进行编译/运行,则不会出现此问题: 您还可以使用选项进行编译,以便将类移动到这样的目录层次结构中: 请注意,您不应使用以开头的程序包名称,JDK的更高版本将引发SecurityExc

  • 我试图用web3j编写一个Java应用程序,它可以读取任意的abi文件,向用户显示AbiDefinitions列表,并让用户调用自己选择的常量函数。我如何计算下面的输出类型? TypeReference 类对泛型类型使用技巧,当泛型类型在源代码中硬编码时,这些技巧可以正常工作,如下所示: 这就是生成的合约包装器要做的。 对于简单类型,我可以这样做: 对于“int256[2]”这样的数组类型,该怎么

  • 我有一个Java JUnit Selenium测试框架来运行一些测试。有两个类,每个类有两个测试。 我有专家肯定火像这样配置 我希望它同时运行4个测试,但是无论我使用什么组合的、和设置,我似乎一次只能运行1个类的测试用例。看起来这应该行得通,有人能提供解决方案吗?

  • 问题内容: 这是执行程序类的方法: 在这里,它等待第二秒,但是当我运行代码时,它将引发异常: 我无法关闭中的并发线程破坏。这是我的代码流: 用Java执行程序类创建一个新线程来运行某些任务,即用 等待10秒以完成任务。 如果任务已完成,则可运行线程也将终止。 如果任务未在10秒内完成,则类应终止线程。 除了在最后一个场景中终止任务以外,其他所有操作都正常。我该怎么办? 问题答案: 该方法只是防止其

  • Java如何在运行时获取一个类的所有对象实例?这个类不一定由Spring管理,也不一定是单例 根据类名+ClassLoader得到所有的类的对象实例,而不是反射并new一个对象

  • 我正在替换一些使用jQuery延迟对象的旧代码,并且正在使用Bluebird/ES6承诺进行重写。 如果我有多个异步调用,那么在所有承诺都解决之后,我如何触发一个函数。 使用jQuery可以进行延迟: 我如何使用ES6 Promise语法重写它?