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

时间:2013-07-09 03:28:54

标签: go packages

我已经使用过GOPATH但是对于这个当前的问题,我面对它并没有帮助。我希望能够创建特定于项目的包:

myproject/
├── binary1.go
├── binary2.go
├── package1.go
└── package2.go

我尝试了多种方式,但如何让package1.gobinary1.gobinary2.go等工作?

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

9 个答案:

答案 0 :(得分:144)

转到依赖关系管理摘要:

  • vgo如果你的go版本是:x >= go 1.11
  • depvendor如果你的go版本是:go 1.6 >= x < go 1.11
  • 如果你的go版本是:x < go 1.6
  • ,则手动

编辑3:Go 1.11的功能vgoreplace dep

要使用vgo,请参阅Modules文档。 TLDR如下:

export GO111MODULE=on
go mod init
go mod vendor # if you have vendor/ folder, will automatically integrate
go build

此方法在项目目录中创建名为go.mod的文件。然后,您可以使用go build构建项目。如果设置了GO111MODULE=auto,则您的项目不能位于$GOPATH


编辑2:vendoring方法仍然有效,无问题。 vendor主要是一个手动流程,因为depvgo已创建。


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


实测值。我可以通过创建GOPATH的子文件夹,然后使用package1import "./package1"脚本中的binary1.go导入来导入包含binary2.go的本地包,如下所示:

binary1.go

...
import (
        "./package1"
      )
...

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

myproject/
├── binary1.go
├── binary2.go
├── package1/
│   └── package1.go
└── package2.go

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

import "../packageX"

答案 1 :(得分:62)

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

只需使用

import "myproject/packageN"

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

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

  • 导入路径可以是全局唯一的。
  • 与GOPATH一起,导入路径可以明确地转换为目录路径。
  • GOPATH下的任何目录路径都可以明确地转换为导入路径。

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

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

答案 2 :(得分:40)

也许你正试图模块化你的包裹。我假设package1package2在某种程度上属于同一个软件包,但为了便于阅读,您可以将这些文件拆分为多个文件。

如果前一个案例属于您,那么您可以在这些多个文件中使用相同的包名称,就像是有相同的文件一样。

这是一个例子:

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中的第一篇文章,所以如果你有一些建议,它会很受欢迎。

答案 3 :(得分:22)

由于引入了 go.mod ,我认为本地和外部软件包管理都变得更加容易。使用 go.mod ,还可以在GOPATH之外进行go项目。

导入本地软件包:

创建文件夹 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

答案 4 :(得分:11)

我有一个类似的问题,当前使用的解决方案使用Go 1.11模块。我有以下结构

- projects
  - go.mod
  - go.sum
  - project1
    - main.go
  - project2
    - main.go
  - package1
    - lib.go
  - package2
    - lib.go

而且我可以使用

从project1和project2导入package1和package2。
import (
    "projects/package1"
    "projects/package2"
)

运行go mod init projects之后。我可以从project1和project2目录中使用go build,也可以从projects目录中使用go build -o project1/exe project1/*.go

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

答案 5 :(得分:8)

您可以使用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

答案 6 :(得分:4)

要向项目添加“本地”包,请添加一个文件夹(例如“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中使用的包名称匹配。换句话说,具有子目录的所有文件应该是相同的包。

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

答案 7 :(得分:2)

创建文件yellow.go

package yellow

func Mix(s string) string {
   return s + "Yellow"
}

然后创建文件orange.go

package main
import "color/yellow"

func main() {
   s := yellow.Mix("Red")
   println(s)
}

如果使用该软件包只有一个程序,则可以使用以下布局:

yellow/yellow.go

orange.go
go.mod

如果使用该程序包有多个程序,则可以使用以下布局:

yellow/yellow.go

orange/orange.go
green/green.go
go.mod

在要创建go mod init color的位置运行go.mod。然后更改为 要构建的文件夹(可能是同一文件夹),然后输入 go build

https://golang.org/doc/code.html

答案 8 :(得分:0)

在bash终端

mkdir <module name>  
cd <module name>  
go mod init <module name>  
touch <module name>.go
  • <module name>.go 中创建 go 包
cd ..  
mkdir main  
cd main  
go mod init main  
touch main.go
  • 创建导入“<module name>”的主包
go mod edit -replace=<module name>=<module path>
go mod tidy
  • 如果您想了解 go 的背景中发生了什么,请查看每个 go.mod 您的文件夹结构将如下所示:
- Project  
  - <module name>  
    - <module name>.go  
    - go.mod  
  - main  
    - main.go  
    - go.mod  
go run .

go build && 
./main.exe