簡體   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