使用Go模块组织程序包中的本地代码

时间:2019-03-31 16:15:07

标签: go go-modules go-packages

main.go之外使用Go模块(go版本> = 1.11)时,找不到从$GOPATH到本地程序包中的某些代码的方法。

我没有导入任何需要包含在go.mod中的外部依赖项,我只是想在本地组织此Go模块的源代码。

文件main.go

package main

// this import does not work
import "./stuff"

func main() {
    stuff.PrintBaz()
}

文件./stuff/bar.go(伪装成本地软件包):

package stuff

import "log"

type Bar struct {
    Baz int
}

func PrintBaz() {
    baz := Bar{42}
    log.Printf("Bar struct: %v", baz)
}

文件go.mod(命令go mod init foo):

module foo

go 1.12

执行go run main.go时:

  • 如果我import "./stuff",那么我会看到build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff
  • 如果我import "stuff",那么我会看到build command-line-arguments: cannot load stuff: cannot find module providing package stuff
  • 如果我import stuff "./stuff"带有软件包别名,那么我会再次看到:build command-line-arguments: cannot find module for path _/home/<PATH_TO>/fooprj/stuff

我找不到使本地软件包与go模块一起使用的方法。

  • 上面的代码怎么了?
  • 如何在使用Go模块(文件go.mod)定义的项目中将本地包导入其他Go代码?

2 个答案:

答案 0 :(得分:13)

模块结构

最常见,最简单的方法是:

  • 每个存储库使用一个go.mod,并且
  • 将单个go.mod文件放在存储库根目录中,并且
  • 使用存储库名称作为module的{​​{1}}行中声明的模块路径
    • (如果您使用的是vanity url,则将使用虚荣网址而不是go.mod中的存储库名称。)

例如,如果您的存储库为go.mod,那么您将在存储库根目录中放置一个github.com/my/repo,第一行显示为go.mod。可以通过module github.com/my/repo进入存储库根目录并运行cd来创建。

下面的内容可以帮助您在使用模块时走上幸福的道路,并且可以避免多个细微之处。

Russ Cox在#26664中发表了评论:

  

对于除高级用户以外的所有用户,您可能希望采用一种惯例,即一个仓库=一个模块。存储库可以包含多个模块对于代码存储选项的长期发展很重要,但是默认情况下,您肯定不需要这样做。

模块Wiki上的"Multi-module Repositories"常见问题解答部分中有关于多模块存储库的更多信息。考虑改写以上建议的任何人都应完整阅读该部分中的那6条左右的FAQ。

在模块中安排包

设置好go mod init github.com/my/repo后,您可以将软件包安排在目录中,但可以在包含go.mod的目录下以及带有{{1 }}。关于如何在程序包中排列代码的三篇好文章:

这些文章是在引入模块之前的经典著作,但其中的思想仍然适用于如何在模块内安排包裹。

将其他软件包导入同一模块中

在导入带有模块的另一个软件包时,始终使用完整路径,包括模块路径。即使在同一模块中导入另一个软件包也是如此。例如,如果某个模块在其go.mod中声明其身份为模块go.mod,而您具有以下组织:

go.mod

然后github.com/my/repo会将其对等包作为repo/ ├── go.mod <<<<< Note go.mod is located in repo root ├── pkg1 │   └── pkg1.go └── pkg2 └── pkg1.go 导入。请注意,您不能使用相对导入路径,例如pkg1import "github.com/my/repo/pkg2"。 (这是上面import "../pkg2"击中OP的一部分。)

模块,存储库,软件包,导入路径

Go模块是一组相关的Go软件包的集合,这些软件包一起作为一个单元进行了版本控制。模块记录精确的依赖要求并创建可复制的构建。

总结存储库,模块和软件包之间的关系:

  • 一个存储库包含一个或多个Go 模块(通常是存储库根目录中的一个模块)。
  • 每个模块包含一个或多个Go
  • 每个软件包都包含一个或多个Go 源文件,这些文件都驻留在单个目录中。
  • 转到源代码:
    • 使用import "./subpkg"语句声明自己的程序包。
    • 自动访问同一程序包中的其他Go源代码。
    • 通过导入语句(例如import "./stuff")中提供的 import path 从另一个包中导入代码。导入路径始终以该程序包的模块路径开头,而不管该程序包是在同一模块中还是在不同模块中。

答案 1 :(得分:7)

首先,您必须为您的项目选择一个名称,并将其写入go.mod文件。该名称属于项目的根目录。您创建的每个新软件包都必须位于其自己的子目录中,并且其名称必须与目录名称匹配。

go.mod:

module myprojectname

module github.com/myname/myproject

然后导入项目的程序包,例如:

import myprojectname/stuff

import github.com/myname/myproject/stuff

软件包stuff的文件必须位于项目的stuff目录中。您可以根据需要命名这些文件。

还可以创建更深的项目结构。例如,您决定将源代码文件与其他文件分开(例如应用程序配置,docker文件,静态文件等)。让我们将stuff目录移到pkg内,pkg/stuff内的每个go文件仍然具有stuff包名称。要导入东西包,只需编写:

import myprojectname/pkg/stuff

没有什么可以阻止您在层次结构中创建更多级别,如github.com/myuser/myproject/pkg/db/provider/postgresql,其中:

  • github.com/myuser/myproject-项目名称。
  • postgresql-程序包名称。
  • pkg/db/provider/postgresql-相对于项目根目录的软件包路径。

您可以在此处了解有关go模块的更多信息:https://github.com/golang/go/wiki/Modules

查看此存储库以获取有关项目组织中使用的各种模式的有用信息:https://github.com/golang-standards/project-layout如果进入pkg目录,您将在其中找到哪些开源项目使用pkg目录它们的结构。