英文:
How to import local packages without gopath
问题
我已经使用了GOPATH
,但对于我现在面临的问题没有帮助。我希望能够创建特定于项目的包:
myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go
我尝试了多种方法,但如何让package1.go
在binary1.go
或binary2.go
中工作呢?
例如;我希望能够import "package1"
,然后能够运行go build binary1.go
,一切都正常工作,而不会抛出找不到包的错误在GOROOT
或GOPATH
上。我需要这种功能的原因是为了大型项目;我不想引用多个其他包或将它们保存在一个大文件中。
英文:
I've used GOPATH
but for this current issue I'm facing it does not help. I want to be able to create packages that are specific to a project:
myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go
I tried multiple ways but how do I get package1.go
to work in the binary1.go
or the binary2.go
and so on?
For example; I want to be able to import "package1"
and then be able to run go build binary1.go
and everything works fine without the error being thrown that the package cannot be found on GOROOT
or GOPATH
. The reason why I need this kind of functionality is for large scale projects; I do not want to have to reference multiple other packages or keep them in one large file.
答案1
得分: 185
Go依赖管理摘要:
- 如果你的Go版本是:
x >= go 1.11
,使用vgo
- 如果你的Go版本是:
go 1.6 >= x < go 1.11
,使用dep
或vendor
- 如果你的Go版本是:
x < go 1.6
,则需要手动管理依赖
编辑3:Go 1.11引入了vgo
特性,将取代dep
。
要使用vgo
,请参阅Modules文档。以下是简要说明:
export GO111MODULE=on
go mod init
go mod vendor # 如果有vendor/文件夹,将自动集成
go build
这种方法会在项目目录中创建一个名为go.mod
的文件。然后可以使用go build
构建项目。如果设置了GO111MODULE=auto
,则项目不能位于$GOPATH
中。
编辑2:依赖管理方法仍然有效,并且没有问题。vendor
是一个相对手动的过程,正因为如此才创建了dep
和vgo
。
编辑1:虽然我的旧方法仍然有效,但不再是“正确”的方法。你应该使用Go 1.6中默认启用的vendor功能、vgo
或dep
(暂时);参见。你可以在vendor
目录中添加你的“外部”或“依赖”包;编译时编译器将首先使用这些包。
找到了。我能够通过在package1
的子文件夹中创建并在binary1.go
和binary2.go
脚本中使用import "./package1"
来导入本地包,如下所示:
binary1.go
...
import (
"./package1"
)
...
所以我的当前目录结构如下:
myproject/
├── binary1.go
├── binary2.go
├── package1/
│ └── package1.go
└── package2.go
我还应该注意到,相对路径(至少在go 1.5中)也是有效的;例如:
import "../packageX"
英文:
Go dependency management summary:
vgo
if your go version is:x >= go 1.11
dep
orvendor
if your go version is:go 1.6 >= x < go 1.11
- Manually if your go version is:
x < go 1.6
Edit 3: Go 1.11 has a feature vgo
which will replace dep
.
To use vgo
, see Modules documentation. TLDR below:
export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build
This method creates a file called go.mod
in your projects directory. You can then build your project with go build
. If GO111MODULE=auto
is set, then your project cannot be in $GOPATH
.
Edit 2: The vendoring method is still valid and works without issue. vendor
is largely a manual process, because of this dep
and vgo
were created.
Edit 1: While my old way works it's not longer the "correct" way to do it. You should be using vendor capabilities, vgo
, or dep
(for now) that are enabled by default in Go 1.6; see. You basically add your "external" or "dependent" packages within a vendor
directory; upon compilation the compiler will use these packages first.
Found. I was able import local package with GOPATH
by creating a subfolder of package1
and then importing with import "./package1"
in binary1.go
and binary2.go
scripts like this :
binary1.go
...
import (
"./package1"
)
...
So my current directory structure looks like this:
myproject/
├── binary1.go
├── binary2.go
├── package1/
│ └── package1.go
└── package2.go
I should also note that relative paths (at least in go 1.5) also work; for example:
import "../packageX"
答案2
得分: 74
没有所谓的“本地包”。磁盘上的包的组织与包的父/子关系无关。包形成的唯一真正的层次结构是依赖树,在一般情况下不反映目录树。
只需使用
import "myproject/packageN"
不要为了没有好理由而与构建系统作斗争。在任何非平凡的程序中,每个导入节省几个字符不是一个好理由,因为例如,具有相对导入路径的项目无法通过go get获取。
导入路径的概念具有一些重要的属性:
- 导入路径可以是全局唯一的。
- 结合GOPATH,导入路径可以明确地转换为目录路径。
- 在GOPATH下的任何目录路径可以明确地转换为导入路径。
所有这些都会被使用相对导入路径破坏。不要这样做。
附注:在Go编译器测试的旧代码中有一些使用相对导入的地方。目前,这是支持相对导入的唯一原因。
英文:
There's no such thing as "local package". The organization of packages on a disk is orthogonal to any parent/child relations of packages. The only real hierarchy formed by packages is the dependency tree, which in the general case does not reflect the directory tree.
Just use
import "myproject/packageN"
and don't fight the build system for no good reason. Saving a dozen of characters per import in any non trivial program is not a good reason, because, for example, projects with relative import paths are not go-gettable.
The concept of import paths have some important properties:
- Import paths can be be globally unique.
- In conjunction with GOPATH, import path can be translated unambiguously to a directory path.
- Any directory path under GOPATH can be unambiguously translated to an import path.
All of the above is ruined by using relative import paths. Do not do it.
PS: There are few places in the legacy code in Go compiler tests which use relative imports. ATM, this is the only reason why relative imports are supported at all.
答案3
得分: 54
也许你正在尝试将你的包模块化。我假设package1
和package2
在某种程度上属于同一个包,但为了可读性,你将它们拆分成多个文件。
如果上述情况是你的情况,你可以在这些多个文件中使用相同的包名,就好像它们是同一个文件一样。
这是一个例子:
add.go
package math
func add(n1, n2 int) int {
return n1 + n2
}
subtract.go
package math
func subtract(n1, n2 int) int {
return n1 - n2
}
donothing.go
package math
func donothing(n1, n2 int) int {
s := add(n1, n2)
s = subtract(n1, n2)
return s
}
我不是Go专家,这是我在StackOveflow上的第一篇帖子,所以如果你有一些建议,我会很乐意接受。
英文:
Perhaps you're trying to modularize your package. I'm assuming that package1
and package2
are, in a way, part of the same package but for readability you're splitting those into multiple files.
If the previous case was yours, you could use the same package name into those multiples files and it will be like if there were the same file.
This is an example:
add.go
package math
func add(n1, n2 int) int {
return n1 + n2
}
subtract.go
package math
func subtract(n1, n2 int) int {
return n1 - n2
}
donothing.go
package math
func donothing(n1, n2 int) int {
s := add(n1, n2)
s = subtract(n1, n2)
return s
}
I am not a Go expert and this is my first post in StackOveflow, so if you have some advice it will be well received.
答案4
得分: 49
自从引入了go.mod,我认为本地和外部包管理都变得更容易了。使用go.mod,可以将go项目放在GOPATH之外。
导入本地包:
创建一个名为demoproject的文件夹,并运行以下命令生成go.mod文件
go mod init demoproject
我在demoproject目录下有以下项目结构。
├── go.mod
└── src
├── main.go
└── model
└── model.go
为了演示目的,在model.go文件中插入以下代码。
package model
type Employee struct {
Id int32
FirstName string
LastName string
BadgeNumber int32
}
在main.go中,我通过引用"demoproject/src/model"来导入Employee模型。
package main
import (
"demoproject/src/model"
"fmt"
)
func main() {
fmt.Printf("Main Function")
var employee = model.Employee{
Id: 1,
FirstName: "First name",
LastName: "Last Name",
BadgeNumber: 1000,
}
fmt.Printf(employee.FirstName)
}
导入外部依赖:
只需在项目目录中运行go get
命令。
例如:
go get -u google.golang.org/grpc
它应该在go.mod文件中包含模块依赖。
module demoproject
go 1.13
require (
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 // indirect
google.golang.org/grpc v1.26.0 // indirect
)
https://blog.golang.org/using-go-modules
英文:
Since the introduction of go.mod , I think both local and external package management becomes easier. Using go.mod, it is possible to have go project outside the GOPATH as well.
Import local package:
Create a folder demoproject and run following command to generate go.mod file
go mod init demoproject
I have a project structure like below inside the demoproject directory.
├── go.mod
└── src
├── main.go
└── model
└── model.go
For the demo purpose, insert the following code in the model.go file.
package model
type Employee struct {
Id int32
FirstName string
LastName string
BadgeNumber int32
}
In main.go, I imported Employee model by referencing to "demoproject/src/model"
package main
import (
"demoproject/src/model"
"fmt"
)
func main() {
fmt.Printf("Main Function")
var employee = model.Employee{
Id: 1,
FirstName: "First name",
LastName: "Last Name",
BadgeNumber: 1000,
}
fmt.Printf(employee.FirstName)
}
Import external dependency:
Just run go get
command inside the project directory.
For example:
go get -u google.golang.org/grpc
It should include module dependency in the go.mod file
module demoproject
go 1.13
require (
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150 // indirect
google.golang.org/grpc v1.26.0 // indirect
)
答案5
得分: 28
我有一个类似的问题,目前我正在使用Go 1.11模块的解决方案。我有以下的结构:
- 项目
- go.mod
- go.sum
- 项目1
- main.go
- 项目2
- main.go
- 包1
- lib.go
- 包2
- lib.go
我可以通过以下方式从项目1和项目2中导入包1和包2:
import (
"projects/package1"
"projects/package2"
)
在运行go mod init projects
之后,我可以从项目1和项目2目录中使用go build
命令,或者可以在项目目录中使用go build -o project1/exe project1/*.go
命令。
这种方法的缺点是所有项目都会共享相同的依赖列表在go.mod文件中。我仍在寻找解决这个问题的方法,但看起来这可能是一个根本性的问题。
英文:
I have a similar problem and the solution I am currently using uses Go 1.11 modules. I have the following structure
- projects
- go.mod
- go.sum
- project1
- main.go
- project2
- main.go
- package1
- lib.go
- package2
- lib.go
And I am able to import package1 and package2 from project1 and project2 by using
import (
"projects/package1"
"projects/package2"
)
After running go mod init projects
. I can use go build
from project1 and project2 directories or I can do go build -o project1/exe project1/*.go
from the projects directory.
The downside of this method is that all your projects end up sharing the same dependency list in go.mod. I am still looking for a solution to this problem, but it looks like it might be fundamental.
答案6
得分: 19
你可以使用replace
go mod init example.com/my/foo
foo/go.mod
module example.com/my/foo
go 1.14
replace example.com/my/bar => /path/to/bar
require example.com/my/bar v1.0.0
foo/main.go
package main
import "example.com/bar"
func main() {
bar.MyFunc()
}
bar/go.mod
module github.com/my/bar
go 1.14
bar/fn.go
package github.com/my/bar
import "fmt"
func MyFunc() {
fmt.Printf("hello")
}
导入本地包与导入外部包类似
只是在go.mod文件中,您将外部包的名称替换为本地文件夹。
文件夹的路径可以是完整的或相对的/path/to/bar
或../bar
- https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive
- https://thewebivore.com/using-replace-in-go-mod-to-point-to-your-local-module/
英文:
You can use replace
go mod init example.com/my/foo
foo/go.mod
module example.com/my/foo
go 1.14
replace example.com/my/bar => /path/to/bar
require example.com/my/bar v1.0.0
foo/main.go
package main
import "example.com/bar"
func main() {
bar.MyFunc()
}
bar/go.mod
module github.com/my/bar
go 1.14
bar/fn.go
package github.com/my/bar
import "fmt"
func MyFunc() {
fmt.Printf("hello")
}
Importing a local package is just like importing an external pacakge
except inside the go.mod file you replace that external package name with a local folder.
The path to the folder can be full or relative /path/to/bar
or ../bar
答案7
得分: 9
要将一个“本地”包添加到您的项目中,添加一个文件夹(例如“package_name”)。并将您的实现文件放在该文件夹中。
src/github.com/GithubUser/myproject/
├── main.go
└───package_name
└── whatever_name1.go
└── whatever_name2.go
在您的package main
中执行以下操作:
import "github.com/GithubUser/myproject/package_name"
其中package_name
是文件夹名称,它必须与文件whatever_name1.go和whatever_name2.go中使用的包名称匹配。换句话说,所有带有子目录的文件都应属于同一个包。
只要在导入中指定父文件夹的完整路径,您可以进一步嵌套更多的子目录。
英文:
To add a "local" package to your project, add a folder (for example "package_name"). And put your implementation files in that folder.
src/github.com/GithubUser/myproject/
├── main.go
└───package_name
└── whatever_name1.go
└── whatever_name2.go
In your package main
do this:
import "github.com/GithubUser/myproject/package_name"
Where package_name
is the folder name and it must match the package name used in files whatever_name1.go and whatever_name2.go. In other words all files with a sub-directory should be of the same package.
You can further nest more subdirectories as long as you specify the whole path to the parent folder in the import.
答案8
得分: 3
运行:
go mod init yellow
然后创建一个文件 yellow.go
:
package yellow
func Mix(s string) string {
return s + "Yellow"
}
然后创建一个文件 orange/orange.go
:
package main
import "yellow"
func main() {
s := yellow.Mix("Red")
println(s)
}
然后构建:
go build
https://golang.org/doc/code.html
英文:
Run:
go mod init yellow
Then create a file yellow.go
:
package yellow
func Mix(s string) string {
return s + "Yellow"
}
Then create a file orange/orange.go
:
package main
import "yellow"
func main() {
s := yellow.Mix("Red")
println(s)
}
Then build:
go build
答案9
得分: 0
在bash终端中
mkdir <模块名称>
cd <模块名称>
go mod init <模块名称>
touch <模块名称>.go
- 在
<模块名称>.go
中创建go包
cd ..
mkdir main
cd main
go mod init main
touch main.go
- 创建导入"
<模块名称>
"的main包
go mod edit -replace=<模块名称>=<模块路径>
go mod tidy
- 如果想要了解go的后台发生了什么,请查看每个go.mod文件
你的文件夹结构将如下所示:
- 项目
- <模块名称>
- <模块名称>.go
- go.mod
- main
- main.go
- go.mod
go run .
或者
go build &&
./main.exe
英文:
In bash terminal
mkdir <module name>
cd <module name>
go mod init <module name>
touch <module name>.go
- Create go package in
<module name>
.go
cd ..
mkdir main
cd main
go mod init main
touch main.go
- create main package that imports "
<module name>
"
go mod edit -replace=<module name>=<module path>
go mod tidy
- look at each go.mod if you want to understand what's happening in go's background
your folder structure will look like:
- Project
- <module name>
- <module name>.go
- go.mod
- main
- main.go
- go.mod
go run .
<strong> OR </strong>
go build &&
./main.exe
答案10
得分: 0
整个晚上都在努力弄清楚为什么我无法访问我的包中的一个函数,一遍又一遍地收到上面的错误消息。简而言之:只能从包外部访问以大写字母开头的函数。
长答案:
项目的结构如下:
-awesomeProject
--- foo
------> foo.go
------> go.mod(<-- 需要删除)
awesome.go
go.mod
- 必须删除foo文件夹中的go.mod文件(如上所述)。仍然想知道为什么我无法访问foo中的函数 -> foo.go
- 必须确保foo中的函数 -> foo.go 以大写字母开头(func Foo... 而不是 func foo ...)。
然后一切都正常工作了。
Jon Bodner在他的书《学习Go - 一种符合实际的Go编程方法》中对这个主题进行了引用:
> “这引出了一个问题:在Go中如何导出标识符?Go不使用特殊关键字,而是使用大写字母来确定包级别的标识符是否在声明它的包之外可见。以大写字母开头的标识符是可导出的。相反,以小写字母或下划线开头的标识符只能从声明它的包内部访问。”
英文:
Spent a whole evening trying to figure out why I am not able to access a function from my package, getting the error message above over and over again. TL;DR: You can only access functions from outside a package that start with an upper case letter.
Long answer:
Project looked like this:
-awesomeProject
--- foo
------> foo.go
------> go.mod (<-- needed to be deleted)
awesome.go
go.mod
- Had to delete the go.mod file in the foo folder (already mentioned above). Still wondering why I could not access my function in foo -> foo.go
- Had to make sure that the function in foo -> foo.go started with an upper case letter (func Foo... instead of func foo ...).
Then everything worked like a charm.
Quote from Jon Bodner's book Learning Go - An Idiomatic Approach to Real-World Go Programming on this topic:
> "This leads to the question: how do you export an identifier in Go? Rather than use a special keyword, Go uses capitalization to determine if a package-level identifier is visible outside of the package where it is declared. An identifier whose name starts with an uppercase letter is exported. Conversely, an identifier whose name starts with a lowercase letter or underscore can only be accessed from within the package where it is declared."
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论