Golang中GitHub和GoPkg的包版本不一致问题求助(新手提问)

Golang中GitHub和GoPkg的包版本不一致问题求助(新手提问)

从GitHub问题页面直接复制的内容

(后来我觉得这里可能是更合适的地方)

你使用的Go版本是什么(go version)?

$ go version
go version go1.14.2 linux/amd64

这个问题在最新版本中是否重现?

你使用的操作系统和处理器架构是什么(go env)?

Debian 10 Buster Stable,Intel® Pentium® G4600 (x86_amd64)

$ uname -a
Linux debian-homepc.bryanpedini.home 4.19.0-8-amd64 #1 SMP Debian 4.19.98-1+deb10u1 (2020-04-27) x86_64 GNU/Linux
`go env` 输出
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/bryanpedini/.cache/go-build"
GOENV="/home/bryanpedini/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/bryanpedini/projects/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build004077584=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

目前正在尝试在家用开发PC上基于Echo框架实例实现一些API。 Go环境一直工作得很好(虽然我自己编码不多,我还在"标准库水平",所以以前从未需要使用版本化包),但现在它开始与包版本搞成一团乱麻。

我正在尝试执行的代码的简化版本:(没有ini配置文件和其它东西) https://play.golang.org/p/IfCwkwtZAew(它不工作)

我的PC输出:

$ go get -u gopkg.in/labstack/echo.v4

$ go run main.go register.go user.go
../../../gopkg.in/labstack/echo.v4/middleware/basic_auth.go:8:2: cannot find package "github.com/labstack/echo/v4" in any of:
/usr/local/go/src/github.com/labstack/echo/v4 (from $GOROOT)
/home/bryanpedini/projects/go/src/github.com/labstack/echo/v4 (from $GOPATH)

$ go get -u github.com/labstack/echo/v4
package github.com/labstack/echo/v4: cannot find package "github.com/labstack/echo/v4" in any of:
/usr/local/go/src/github.com/labstack/echo/v4 (from $GOROOT)
/home/bryanpedini/projects/go/src/github.com/labstack/echo/v4 (from $GOPATH)

$ go get -u github.com/labstack/echo

$ go run main.go register.go user.go
# command-line-arguments
./main.go:13:38: cannot use middleware.RemoveTrailingSlash() (type "github.com/labstack/echo".MiddlewareFunc) as type "gopkg.in/labstack/echo.v4".MiddlewareFunc in argument to e.Pre

稍微修改的版本: https://play.golang.org/p/1PhlgeDA32V(它会超时,这清楚地告诉我Echo服务器启动了)

最后,同一段代码在我电脑上的结果(基本上只是更改了导入):

$ go run main.go register.go user.go
main.go:7:2: cannot find package "github.com/labstack/echo/v4" in any of:
/usr/local/go/src/github.com/labstack/echo/v4 (from $GOROOT)
/home/bryanpedini/projects/go/src/github.com/labstack/echo/v4 (from $GOPATH)
main.go:8:2: cannot find package "github.com/labstack/echo/v4/middleware" in any of:
/usr/local/go/src/github.com/labstack/echo/v4/middleware (from $GOROOT)
/home/bryanpedini/projects/go/src/github.com/labstack/echo/v4/middleware (from $GOPATH)

在VSCode的linter(微软官方的Go扩展)中,我得到相同的"无法导入github/labstack/echo/v4(没有github/labstack/echo/v4的包)"…

最后但同样重要的是,让我们尝试不带版本号,好吗?Linter vs 编译器… 战斗开始: linter首先发起攻击

Screenshot_20200508_221125

然后Echo微服务器将linter击倒KO,因为它实际上运行良好… 就像,什么情况?

你期望看到什么?

一个易于使用的版本控制系统叫做gopkg.in

你实际看到了什么?

一团我无法描述的 几乎从不工作的混乱,带有难以猜测的导入路径,有时工作,有时不工作(而且由于谷歌搜索功能的错误,普遍缺乏对我问题的理解:你愚蠢的AI没理解"我可以从github导入go包但不能从gopkg导入"的哪部分?就找到我2003年的论坛帖子,好吗?引用:古人的智慧)

GitHub问题复制结束

在我深入探索之前,还有什么我应该尝试/需要知道的吗?或者因为我对Go包工作原理的(不/错误)理解而遭受更多头痛? 有没有人知道像指南或容易"进入思维体系"的东西?因为语言本身相当直接,非常像Cpp,而且(对我来说)容易开始理解和立即编写… 但是技术方案,伙计!!把文件放在"src"文件夹里,然后是一个以git平台命名的目录,接着是你的用户名,最后是项目名称,嗯,这很容易;但是如果我曾经理解过我观看的每个教程中关于包、它们的结构和导入方案的任何一点(现在比以往任何时候都更甚,随着包模块版本化的(几乎)新引入)…

提前感谢大家,对这篇长文表示抱歉(如前所述,这是从GitHub问题模板复制的,非常详细)。


更多关于Golang中GitHub和GoPkg的包版本不一致问题求助(新手提问)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

欢迎来到 Go 论坛 🚀 🎆


在整体回答问题之前:当你进行原型开发时,你是在 go 模块内部进行开发吗?

编辑:你的项目目录中应该有一个 go.mod 文件。

// 代码示例应放在这里,但原文未提供具体代码

更多关于Golang中GitHub和GoPkg的包版本不一致问题求助(新手提问)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您的欢迎!

关于您的问题:我其实不太清楚。我的做法是,在 $GOPATH 下按照规范的结构创建一个新文件夹,然后创建一个 main.go 文件并立即开始编码。 我听说过这个 go.mod 文件,但实际上从未创建过,也还没学习如何使用它。

这是否意味着,当我开始编写有依赖关系的代码时,应该首先关注这个文件作为“起点”? 因为我觉得有点奇怪,代码明明可以运行,但我的 VSCode 语法检查器却给出了类似这样的提示……

Screenshot_20200509_190502

好的……

现在,在到处执行了一些 go mod initgo mod tidy 之后,代码和 linter 都运行正常了。 我仍然不明白的是,为什么在用 go mod tidy 生成 go.modgo.sum 文件之前,同样的导入(在这个例子中是 github.com/labstack/echo/v4)会报错,而没有版本号时却能工作;但现在即使加上版本号也能工作了…… 这到底是怎么回事?我的意思是,如果是因为 go.mod 文件指示 go build 工具去选取这个那个依赖并正常工作,那当然,我很高兴;但现在我想理解为什么连 linter 之前也报错,而现在一切都好了。我并不真的认为 VSCode 的 linter 会去检查 go mod 文件来看是否一切正常,所以我不太明白这个情况……

好吧,当一切正常运转时,一切就都好了,对吧?

现在代码和linter都运行得很好。

嗯,毕竟当一切正常时,一切都好,对吧?

我还没有亲自创建一个git仓库来测试,但如果一切正常,那么我的假设是正确的:你之前使用的是传统的Go包开发方式

我仍然不明白的是,为什么在通过 go mod tidy 生成 go.modgo.sum 文件之前,相同的代码导入(本例中是 github.com/labstack/echo/v4)会报错,而没有版本号时却能工作;但现在即使加上版本号也能工作了…

go.modgo.sum 是记录这些依赖项校验和的工具)本质上是一个类似于Ruby中Gemfile的包版本“记录”工具。它的设计有多重目标:

  1. 对你的包的所有依赖项进行版本控制(在你的例子中是v4版本的echo)。
  2. 允许开发者在 GOPATH 之外进行开发。
  3. 通过从GOPATH的滚动更新策略切换到Go Module的定点发布策略,消除依赖管理地狱。
  4. 将第三方包的导入方式(有 vendorgodep 等多种方式)统一为一种导入方式。

这些都是Go传统开发方式中存在的问题。这就是为什么在 go.mod 初始化之后,很多复杂的事情已经在后台为你处理好了。这是如今构建Go包(无论是二进制程序还是库包)新的、可接受的方式。

在继续深入之前,你应该阅读并理解Go模块,以便让你的工作区跟上节奏:使用Go模块 - Go编程语言。Go模块有严格的规则需要遵守。

这是一个典型的Go模块版本管理问题,主要原因是gopkg.in和GitHub仓库之间的版本映射不一致,以及Go模块系统与旧版GOPATH模式的冲突。

问题分析

从你的go env输出可以看到:

  • GO111MODULE="" - 这是空值,Go会根据项目位置自动选择模式
  • GOPATH模式仍在生效
  • 你混合使用了gopkg.ingithub.com两种导入路径

解决方案

方案1:启用Go模块(推荐)

在你的项目根目录执行:

# 初始化Go模块
go mod init your-project-name

# 清理旧的包缓存
go clean -modcache

# 获取echo包
go get github.com/labstack/echo/v4

然后更新你的main.go,使用正确的导入路径:

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
)

func main() {
    e := echo.New()
    
    // 使用正确的中间件
    e.Pre(middleware.RemoveTrailingSlash())
    
    e.GET("/", func(c echo.Context) error {
        return c.String(200, "Hello, World!")
    })
    
    e.Logger.Fatal(e.Start(":1323"))
}

方案2:使用正确的gopkg.in导入

如果你坚持使用gopkg.in,需要确保所有相关包都来自同一源:

package main

import (
    "gopkg.in/labstack/echo.v4"
    "gopkg.in/labstack/echo.v4/middleware"
)

func main() {
    e := echo.New()
    
    e.Pre(middleware.RemoveTrailingSlash())
    
    e.GET("/", func(c echo.Context) error {
        return c.String(200, "Hello, World!")
    })
    
    e.Logger.Fatal(e.Start(":1323"))
}

然后获取依赖:

go get gopkg.in/labstack/echo.v4

方案3:强制启用Go模块

设置环境变量强制使用模块模式:

export GO111MODULE=on
cd /your/project/path
go mod init
go get github.com/labstack/echo/v4

验证步骤

创建测试文件验证导入是否正常:

// test_import.go
package main

import (
    "fmt"
    "github.com/labstack/echo/v4"
)

func main() {
    e := echo.New()
    fmt.Printf("Echo version: %v\n", e)
}

运行测试:

go run test_import.go

关键点

  1. 不要混合使用gopkg.ingithub.com导入 - 选择一种并保持一致
  2. Go模块是未来 - 建议迁移到模块系统
  3. 版本后缀 - v4表示主版本,在Go模块中必须体现在导入路径中

你的代码示例中类型不匹配错误正是因为同时导入了两个不同路径的echo包,Go编译器将它们视为完全不同的类型。

回到顶部