Как получить имя текущего пакета в 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)
}

но мне интересно, если вы можете избежать этого

Ответ 1

Существует не runtime или reflect метод, который предоставляет функциональные возможности, которые вы ищут.

Самое близкое, что я мог найти, это:

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))
}

Ответ 2

Вот часть моего регистрационного пакета. Он извлекает информацию о вызывающем абоненте функции ведения журнала, чтобы показать ее позже на выходе.

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,
    }
}

Как вы можете видеть, он также возвращает имя пакета.

Ответ 3

Чтобы надежно получить имя пакета, вы можете использовать синтаксический анализатор go для анализа только предложения пакета.

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
}

Ответ 4

Это может помочь:

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
}