Go 1.11 rc1 中 Go Modules 的使用指南

Go 1.11 rc1 中 Go Modules 的使用指南 作为早期采用者,我一直将 GO111MODULE=on 作为永久设置来运行 Go,因为这将很快成为默认设置,所以我不妨现在就习惯它。

某些基于 Github 的包似乎与 Go 模块配合得非常好。Go get 可以正常工作,尽管它似乎下载到 ~/golang/pkg/mod/github.com/<repo> 而不是 ~/golang/src/etc...

其他包则完全无法正常工作。有些会报错 go: cannot find main module; see 'go help modules'。这个错误似乎可以通过运行 go mod init 来解决。唯一的问题是这会导致鸡生蛋蛋生鸡的情况,因为如果 go get 尚未执行,那么应该在何处运行 go mod init。选择父文件夹运行 go mod init 并不令人满意,因为这不可避免地会导致大量虚拟的 go.mod 文件散落在文件系统中。

因此,我有几个问题:

  • 我是否应该暂时退出前沿,坚持使用 GO111MODULE=auto?我应该在何处运行我的 go get 命令?
  • 如果我在 ~ 下运行它们,这位于 $GOPATH 之外,使用 auto 模式时,这与在 ~/go 下运行会有什么不同吗?
  • 如果我坚持使用 GO111MODULE=on,从 github 或其他仓库获取 go 代码的推荐方式是什么?
  • Dave Cheney 在 vgo 时期的一篇早期文章显示他使用 git clone 后跟 go mod init,完全避免使用 go get。这肯定不是推荐的方法吧?

就像我说的,当 Go 模块正常工作时,它确实非常出色。当它不工作时,似乎违背了所有逻辑,而且似乎没有足够的文档来覆盖人们必然会遇到的问题。

我欢迎更有经验的 Gopher 们的想法。我相信你们就在那里!

有任何想法吗?


8 回复

啊!我现在明白了。感谢克里斯,你的解释非常清晰明了!


你是说 go get 只适用于非主包吗?

看起来你是对的。从为用户提供最少意外原则的角度来看,我认为这个问题本可以处理得更好。

ChrisHines:

我认为使用 go get 安装主包的功能尚未实现

但我确信我曾经对某些包使用过 go get

carlca:

然而我确信自己曾对某些包使用过 go get 命令。

这些会不会是非主包呢?

我认为使用 go get 安装主包的功能尚未实现,但已在路线规划中。我的判断基于以下议题讨论:https://github.com/golang/go/issues/24250#issuecomment-377553022

某种程度上是这样。目前,在 Go 1.11 rc1 的模块模式下,go get 需要 go.mod 文件才能正常工作。因此,如果您在一个包含 go.mod 文件的项目中工作,并且需要添加对库包(非主包)的依赖,或者更新您正在使用的库包,那么 go get <package> 可以很好地工作。它会找到并下载请求的包,并使用包的模块的 require 规范更新项目的 go.mod 文件。

另一方面,如果您试图下载、编译和安装别人在 github.com 或类似网站上发布的主包——这是我们多年来一直使用 go get 做的事情——在 Go 1.11 rc1 的模块模式下,这并不太顺利。这里存在一个先有鸡还是先有蛋的问题。go get 需要一个模块文件,但在获取您试图获取的包的模块之前,它不会有这样的文件。

在我上面链接的问题评论中,有人非常强烈地表示 go get 需要支持在没有预先存在的 go.mod 文件的情况下安装主包“最终”,但接着提出了几个关于实现细节的开放性问题。

换句话说,这是他们打算实现的一个功能,但在 1.11 rc1 中尚未实现。

在Go 1.11 rc1中使用Go Modules时,确实需要一些调整来适应新的工作流。以下是对你问题的具体解答:

关于GO111MODULE设置

建议保持GO111MODULE=on,因为这是未来的方向。问题通常出现在工作目录设置上。

正确的Go Modules工作流

1. 初始化新项目

# 在项目目录外创建目录
mkdir myproject && cd myproject
go mod init github.com/yourname/myproject

2. 获取依赖

# 直接导入包,go mod会自动处理依赖
go get github.com/some/dependency

或者直接在代码中导入:

package main

import (
    "fmt"
    "github.com/gin-gonic/gin" // go mod会自动下载
)

func main() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(200, "Hello Modules")
    })
    r.Run()
}

解决"cannot find main module"错误

这个错误表明你不在包含go.mod文件的目录中。解决方案:

# 确保在项目根目录(包含go.mod)中操作
cd /path/to/your/project
go get github.com/some/package

关于工作目录位置

GO111MODULE=on模式下:

  • 可以在任何目录工作,不限于$GOPATH
  • ~/~/go在模块模式下行为相同
  • 模块依赖存储在$GOPATH/pkg/mod

推荐的获取代码方式

对于新项目,推荐流程:

# 1. 创建项目目录
mkdir newproject && cd newproject

# 2. 初始化模块
go mod init example.com/newproject

# 3. 编写代码或直接获取依赖
go get github.com/pkg/errors@v0.8.1

对于现有项目迁移:

cd existing-project
go mod init
go mod tidy  # 自动分析依赖并更新go.mod

关于Dave Cheney的方法

使用git clone后跟go mod init在某些场景下确实有效,特别是:

  • 当你需要特定分支或提交时
  • 当仓库有复杂的子模块时
  • 当需要离线开发时

示例:

git clone https://github.com/user/repo.git
cd repo
go mod init github.com/user/repo

但这确实不是标准工作流。标准做法是使用go get,因为它能正确处理版本管理和依赖解析。

Go Modules在1.11中是实验性功能,确实存在一些边界情况。随着版本更新,这些问题会逐步解决。目前坚持使用GO111MODULE=on并遵循上述模式是最佳选择。

回到顶部