繁体   English   中英

如何在go中获取当前包的名称?

[英]How to get name of current package in go?

有没有办法在运行时获取当前包的名称?

package main

import "fmt"

func main() {
    pkgName := {some magic here:)}
    fmt.Println(pkgName)
}

...结果应该是“主要”

现在我正在使用常量,例如:

package main

import "fmt"
const (
    pkgName = "main"
)

func main() {
    fmt.Println(pkgName)
}

但我很好奇你是否可以避免这种情况

这是我的记录器包的一部分。 它检索有关日志记录函数调用者的信息,以便稍后在输出中显示它。

func retrieveCallInfo() *callInfo {
    pc, file, line, _ := runtime.Caller(2)
    _, fileName := path.Split(file)
    parts := strings.Split(runtime.FuncForPC(pc).Name(), ".")
    pl := len(parts)
    packageName := ""
    funcName := parts[pl-1]

    if parts[pl-2][0] == '(' {
        funcName = parts[pl-2] + "." + funcName
        packageName = strings.Join(parts[0:pl-2], ".")
    } else {
        packageName = strings.Join(parts[0:pl-1], ".")
    }

    return &callInfo{
        packageName: packageName,
        fileName:    fileName,
        funcName:    funcName,
        line:        line,
    }
}

如您所见,它也会返回包名称。

没有提供您正在寻找的功能的运行时反射方法或功能。

我能找到的最接近的是:

package main

import (
    "azul3d.org/lmath.v1"
    "fmt"
    "reflect"
)

type Empty struct{}

func main() {
    fmt.Println(reflect.TypeOf(Empty{}).PkgPath())
    fmt.Println(reflect.TypeOf(lmath.Vec3{0, 0, 0}).PkgPath())
}

这将输出:

main
azul3d.org/lmath.v1

您还可以读取文件的第一行并删除“package”子字符串。 (不确定这是不是最好的主意)

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("so.go")
    if err != nil {
        panic(err)
    }
    r := bufio.NewReader(file)
    line, _, err := r.ReadLine()
    if err != nil {
        panic(err)
    }
    packageName := bytes.TrimPrefix(line, []byte("package "))
    fmt.Println(string(packageName))
}

要可靠地获取包名称,可以使用go编译器的解析器来仅解析package子句。

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/token"
)

func packageName(file string) (string, error) {
    fset := token.NewFileSet()

    // parse the go soure file, but only the package clause
    astFile, err := parser.ParseFile(fset, l.path, nil, parser.PackageClauseOnly)
    if err != nil {
        return "", err
    }

    if astFile.Name == nil {
        return "", fmt.Errorf("no package name found")
    }

    return astFile.Name.Name, nil
}

这可能有所帮助:

import (
    "runtime"
    "strings"
)

func Package() string {
    pc, _, _, _ := runtime.Caller(1)
    parts := strings.Split(runtime.FuncForPC(pc).Name(), ".")
    pl := len(parts)
    pkage := ""
    funcName := parts[pl-1]
    if parts[pl-2][0] == '(' {
        funcName = parts[pl-2] + "." + funcName
        pkage = strings.Join(parts[0:pl-2], ".")
    } else {
        pkage = strings.Join(parts[0:pl-1], ".")
    }
    return pkage
}

更好的解决方案

我实际上找到了一个更好的解决方案,在这里的这个函数中,你只需简单地传递一个函数,输出就会简单而直接。

package main

import (
    "reflect"
    "runtime"
    "strings"
)

func GetPackageName(temp interface{}) string {
    strs := strings.Split((runtime.FuncForPC(reflect.ValueOf(temp).Pointer()).Name()), ".")
    strs = strings.Split(strs[len(strs)-2], "/")
    return strs[len(strs)-1]
}

这是您如何使用它的示例:

package main

import "fmt"

func main() {
    fmt.Println(GetPackageName(main))
}

这是您应该期待的答案:

main

这是我的一个应用程序中技术含量非常低的解决方案,这将返回一个变量来自的包:

func pkgName(x interface{}) string {
    varType := strings.TrimPrefix(fmt.Sprintf("%T", x), "*")
    return strings.TrimSuffix(varType, path.Ext(varType))
}

要获取当前包,请在本地声明一个变量并将其传入。

暂无
暂无

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

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