Golang如何在没有gopath的情况下导入本地包?

145 package go

我已经习惯GOPATH但是对于这个当前的问题,我面临的并没有帮助.我希望能够创建特定于项目的包:

myproject/
??? binary1.go
??? binary2.go
??? package1.go
??? package2.go
Run Code Online (Sandbox Code Playgroud)

我试过多种方法,但我如何才能package1.go在工作binary1.gobinary2.go等等?

例如; 我希望能够import "package1",然后能够运行go build binary1.go,一切正常,没有错误被抛出,无法找到包GOROOTGOPATH.我需要这种功能的原因是大型项目; 我不想引用多个其他包或将它们保存在一个大文件中.

小智 164

去依赖管理摘要:

  • vgo 如果您的go版本是: x >= go 1.11
  • dep或者vendor你的go版本是:go 1.6 >= x < go 1.11
  • 手动,如果您的go版本是: x < go 1.6

编辑3:Go 1.11有一个vgo取代 的功能dep.

要使用vgo,请参阅模块文档.TLDR如下:

export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build
Run Code Online (Sandbox Code Playgroud)

此方法创建go.mod在projects目录中调用的文件.然后,您可以使用go build.如果GO111MODULE=auto设置,那么您的项目不能进入$GOPATH.


编辑2:vendoring方法仍然有效,并且没有问题.vendor在很大程度上是一个手动过程,因此depvgo创建了.


编辑1:虽然我的旧方式有效,但它不再是"正确"的方式.您应该使用在Go 1.6中默认启用的供应商功能,vgodep(现在); .您基本上在vendor目录中添加"外部"或"从属"包; 在编译时,编译器将首先使用这些包.


发现.我可以GOPATH通过创建一个子文件夹导入本地包,package1然后用import "./package1"in binary1.go和import这样导入binary2.go:

binary1.go

...
import (
        "./package1"
      )
...
Run Code Online (Sandbox Code Playgroud)

所以我当前的目录结构如下所示:

myproject/
??? binary1.go
??? binary2.go
??? package1/
?   ??? package1.go
??? package2.go
Run Code Online (Sandbox Code Playgroud)

我还应该注意到相对路径(至少在1.5中)也有效; 例如:

import "../packageX"
Run Code Online (Sandbox Code Playgroud)

  • 相对导入路径是一个[坏主意](https://golang.org/cmd/go/#hdr-Relative_import_paths). (11认同)
  • `import"../ package1"` (7认同)
  • 这有效,直到你有两个子文件夹,其中一个引用另一个.例如,如果package2也是一个子文件夹并且它需要package1,则系统会中断. (4认同)

zzz*_*zzz 66

没有"本地包"这样的东西.磁盘上的包的组织与包的任何父/子关系正交.包形成的唯一真正的层次结构是依赖树,在一般情况下它不反映目录树.

只是用

import "myproject/packageN"
Run Code Online (Sandbox Code Playgroud)

并且没有充分理由不与构建系统作斗争.在任何非平凡的程序中为每个导入保存十几个字符并不是一个好理由,因为,例如,具有相对导入路径的项目不具有可获得性.

导入路径的概念具有一些重要属性:

  • 导入路径可以是全局唯一的.
  • 与GOPATH结合使用,可以将导入路径明确转换为目录路径.
  • GOPATH下的任何目录路径都可以明确地转换为导入路径.

以上所有内容都是通过使用相对导入路径来破坏的.不要做.

PS:Go编译器测试中遗留代码中使用相对导入的地方很少.ATM,这是支持相对进口的唯一原因.

  • 我认为这是不好的建议.例如,如果您最终使用gopkg.in进行版本控制,那么您对"迷你"包装的绝对导入路径运气不佳,如上所述.要么你破坏了源代码库,要么版本化的代码变得无用. (7认同)
  • 我建议你看一下这个介绍视频,以便更好地理解**包**和**GOPATH**.https://www.youtube.com/watch?v=XCsL89YtqCs (2认同)

Jua*_*res 42

也许你正试图模块化你的包装.我假设package1并且package2在某种程度上是同一个包的一部分,但为了便于阅读,你将它们分成多个文件.

如果前面的案例是你的,你可以在这些倍数文件中使用相同的包名称,就好像有相同的文件一样.

这是一个例子:

add.go

package math

func add(n1, n2 int) int {
   return n1 + n2
}
Run Code Online (Sandbox Code Playgroud)

subtract.go

package math

func subtract(n1, n2 int) int {
    return n1 - n2
}
Run Code Online (Sandbox Code Playgroud)

donothing.go

package math

func donothing(n1, n2 int) int {
    s := add(n1, n2)
    s = subtract(n1, n2)
    return s
}
Run Code Online (Sandbox Code Playgroud)

我不是Go专家,这是我在StackOveflow中的第一篇文章,所以如果你有一些建议,它会很受欢迎.


小智 36

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
Run Code Online (Sandbox Code Playgroud)

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
}

Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)

Import external dependency:

Just run go get command inside the project directory.

For example:

go get -u google.golang.org/grpc
Run Code Online (Sandbox Code Playgroud)

它应该在 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
)
Run Code Online (Sandbox Code Playgroud)

https://blog.golang.org/using-go-modules


Mad*_*bat 17

我有类似的问题,我目前使用的解决方案使用Go 1.11模块.我有以下结构

- projects
  - go.mod
  - go.sum
  - project1
    - main.go
  - project2
    - main.go
  - package1
    - lib.go
  - package2
    - lib.go
Run Code Online (Sandbox Code Playgroud)

我可以通过使用从project1和project2导入package1和package2

import (
    "projects/package1"
    "projects/package2"
)
Run Code Online (Sandbox Code Playgroud)

跑完之后go mod init projects.我可以使用go buildproject1和project2目录,或者我可以go build -o project1/exe project1/*.go从projects目录中进行操作.

这种方法的缺点是所有项目最终都会在go.mod中共享相同的依赖项列表.我仍然在寻找这个问题的解决方案,但看起来它可能是基本的.


Tim*_*nen 12

您可以使用 replace

go mod init example.com/my/foo
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

foo/main.go

package main
import "example.com/bar"

func main() {
    bar.MyFunc()
}
Run Code Online (Sandbox Code Playgroud)

酒吧/go.mod

module github.com/my/bar

go 1.14
Run Code Online (Sandbox Code Playgroud)

酒吧/fn.go

package github.com/my/bar

import "fmt"

func MyFunc() {
    fmt.Printf("hello")
}
Run Code Online (Sandbox Code Playgroud)

导入本地包就像导入外部包

除了在 go.mod 文件中,您用本地文件夹替换该外部包名称。

文件夹的路径可以是完整的或相对的/path/to/bar../bar


Hom*_*man 7

要将“本地”包添加到项目中,请添加一个文件夹(例如“ package_name”)。并将您的实现文件放在该文件夹中。

src/github.com/GithubUser/myproject/
 ??? main.go
 ????package_name
       ??? whatever_name1.go
       ??? whatever_name2.go
Run Code Online (Sandbox Code Playgroud)

在您package main这样做:

import "github.com/GithubUser/myproject/package_name"
Run Code Online (Sandbox Code Playgroud)

package_name文件夹名称在哪里,它必须与文件what_name1.go和what_name2.go中使用的包名称匹配。换句话说,所有带有子目录的文件都应位于同一软件包中。

只要您在导入中指定父文件夹的完整路径,就可以进一步嵌套更多子目录。

  • 不适用于私有存储库。 (4认同)
  • 这是一个很好的建议,除了在任何内核恐慌期间,从二进制文件转储的堆栈跟踪会显示github.com路径,例如,并不总是最理想的行为。有一些标志可以抑制这种情况,但是它并不一定只是为了实现简单的包组织而已,我发现它确实有时会失败。 (2认同)
  • `package myproject/package_name 不在 GOROOT (/usr/lib/go-1.14/src/myproject/package_name)` (2认同)