为什么“go run”命令在主包中找不到第二个文件?

xmd2e60i  于 2023-09-28  发布在  Go
关注(0)|答案(3)|浏览(95)

我遇到一个问题,其中go run main.go产生错误:

# command-line-arguments
./main.go:9: undefined: test

但是,go build && ./goruntest命令可以很好地编译和运行程序。
输出为:
Hi from test()
sameFileTest()
您好,来自pkgtest.Test()
Hi from pkgtest.Test1()
我的目录设置如下:

go/src/github.com/username/goruntest/
    pkgtest/
        pkgtest.go
        pkgtest1.go
    main.go
    test2.go

这里是代码。

main.go

package main

import (
    "fmt"
    "github.com/username/goruntest/pkgtest"
)

func main() {
    fmt.Println(test())           // main.go:9
    fmt.Println(sameFileTest())
    fmt.Println(pkgtest.Test())
    fmt.Println(pkgtest.Test1())
}

func sameFileTest() string {
    return "Hi from sameFileTest()"
}

gotest1.go

package main

func test() string {
    return "Hi from test()"
}

pkgtest/pkgtest.go

package pkgtest

func Test() string {
    return "Hi from pkgtest.Test()"
}

pkgtest/pkgtest1.go

package pkgtest

func Test1() string {
    return "Hi from pkgtest.Test1()"
}

我明白问题是第二个文件作为package main的一部分,我也明白没有真实的的理由在main中有第二个文件。

**我的问题是:**为什么go run无法处理这个设置,但构建和运行可执行文件却可以正常工作?
编辑

pkgtest中包含第二个文件
我也知道命令go run main.go gotest1.go可以工作,但为什么我需要指定gotest1.go
为了简洁起见,我最初省略了这些细节。但现在我明白它们对这个问题很重要。

yptwkmov

yptwkmov1#

尝试将所有相关文件提供给go run

$ go help run
usage: go run [build flags] [-exec xprog] gofiles... [arguments...]

Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
cgvd09ve

cgvd09ve2#

我想在这里分享一些有用的资源以供参考,这些资源是我从另一个类似的已删除帖子中学到的。它看起来像一个简单的命令,但你可能不完全知道它。
1.如果您向go run提供源文件列表,那么您创建的是一个单独的合成包,构建约束将被忽略。因此,与其列出go文件,不如使用导入路径或文件系统路径,例如。go run .。用go help packages检查:

As a special case, if the package list is a list of .go files from a
single directory, the command is applied to a single synthesized
package made up of exactly those files, ignoring any build constraints
in those files and ignoring any other files in the directory.

1.可执行目标以第一个源文件命名。在go run命令here(第80和125行)和here(第2506行)的实现中检查它:

// GoFilesPackage creates a package for building a collection of Go files
// (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main.
func GoFilesPackage(ctx context.Context, gofiles []string) *Package {
...

1.为了避免在包初始化过程中出现潜在的问题,我们建议您按照词法文件名顺序提供go文件的列表。在specs中查看:

The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on.
...
A package with no imports is initialized by assigning initial values to all its package-level variables followed by calling all init functions in the order they appear in the source, possibly in multiple files, as presented to the compiler.
...
To ensure reproducible initialization behavior, build systems are encouraged to present multiple files belonging to the same package in lexical file name order to a compiler.

1.有关于go run的历史讨论,请检查herehere

vjhs03f7

vjhs03f73#

运行当前包(目录)中所有*.go文件的最简单方法是

go run .

如上所述,这种方法允许您在一个目录中使用类似脚本的*.go文件,并运行其中任何一个文件,而不受其他文件的干扰。

相关问题