详解golang中 work与 module 的区别与联系

 更新时间:2023年09月27日 08:25:41   作者:demo007x  
Go 模块通常由一个项目或库组成,并包含一组随后一起发布的 Go 包,Go 模块通过允许用户将项目代码放在他们选择的目录中并为每个模块指定依赖项的版本,解决了原始系统的许多问题,本文将给大家介绍一下golang中 work与 module 的区别与联系,需要的朋友可以参考下

一文掌握 golang中 work与 module 的区别与联系

在 1.13 版本中,Go 的作者添加了一种管理 Go 项目所依赖的库的新方法,称为Go 模块go mod。添加 Go 模块是为了满足日益增长的需求,使开发人员更容易维护其依赖项的各种版本,并为开发人员在计算机上组织项目的方式增加更多灵活性。

Go 模块通常由一个项目或库组成,并包含一组随后一起发布的 Go 包。GOPATHGo 模块通过允许用户将项目代码放在他们选择的目录中并为每个模块指定依赖项的版本,解决了原始系统的许多问题。

前面已经详细介绍过了 go module 的使用教程。golang 项目开发如何创建自己的 Module

我们在项目开发的时候不仅仅需要使用别人开发的开源模块,虽然自己公司内部项目的增加回积累

我们在项目开发的时候不仅仅需要使用别人开发的开源模块,虽然自己公司内部项目的增加回积累很多适合自己公司的 golang 的模块来提供给自己公司的其他项目成员使用。比如 sso module 等。

使用 module 开发模块的弊端

我们在使用 golang 的 module 来开发模块的时候需要在项目的go.mod文件中引入对应的项目,但是golang 默认会去相对应的地址去拉去对应的包,但是这个时候我们的module 并没有提交到自己的仓库中。那么这个时候golang 就会报错,找不到对应的 package。

那么这个时候应该怎么做呢?一般的做法就是在 go.mod 文件中添加一条指令 replace

 module example.com/hello
 ​
 go 1.20
 ​
 replace example.com/greetings => ../greetings
 ​
 require example.com/greetings v0.0.0-00010101000000-000000000000

这样就可以在我们的项目中使用正在开发中的包。

虽然可以满足我们开发包的依赖问题,但是会存在一个严重的问题:一旦我们开发完成将 module 提交到了代码仓库,忘记将 `replace example.com/greetings => ../greetings 其他成员拉去了最新的包,在执行 go mod tidy 就会提示找不到包的问题,因为 replace 指令会得到优先执行,并不会从仓库中拉去对应的模块。

使用 go work 解决 replace 指令的问题

在Go1.18 正式发布后,有了新的模式,那就是 go work 工作区模式(Workspace mode),并不是之前 GOPATH 时代的 Workspace,而是希望在本地开发时支持多 Module

针对 mo module 的问题,Michael Matloob 提出了 Workspace Mode(工作区模式)。相关 issue 讨论:cmd/go: add a workspace modeProposal,感兴趣的可以去参阅。

所以要想使用 go work,那基本的要求就是你的 golang version 必须是 golang 1.18 以上的版本

 ❯ go version
 go version go1.20.7 darwin/amd64

我们先看看 go wokr 相关的命令:在命令行执行go help work

 ❯ go help work
 Work provides access to operations on workspaces.
 ​
 Note that support for workspaces is built into many other commands, not
 just 'go work'.
 ​
 See 'go help modules' for information about Go's module system of which
 workspaces are a part.
 ​
 See https://go.dev/ref/mod#workspaces for an in-depth reference on
 workspaces.
 ​
 See https://go.dev/doc/tutorial/workspaces for an introductory
 tutorial on workspaces.
 ​
 A workspace is specified by a go.work file that specifies a set of
 module directories with the "use" directive. These modules are used as
 root modules by the go command for builds and related operations.  A
 workspace that does not specify modules to be used cannot be used to do
 builds from local modules.
 ​
 go.work files are line-oriented. Each line holds a single directive,
 made up of a keyword followed by arguments. For example:
 ​
   go 1.18
 ​
   use ../foo/bar
   use ./baz
 ​
   replace example.com/foo v1.2.3 => example.com/bar v1.4.5
 ​
 The leading keyword can be factored out of adjacent lines to create a block,
 like in Go imports.
 ​
   use (
     ../foo/bar
     ./baz
   )
 ​
 The use directive specifies a module to be included in the workspace's
 set of main modules. The argument to the use directive is the directory
 containing the module's go.mod file.
 ​
 The go directive specifies the version of Go the file was written at. It
 is possible there may be future changes in the semantics of workspaces
 that could be controlled by this version, but for now the version
 specified has no effect.
 ​
 The replace directive has the same syntax as the replace directive in a
 go.mod file and takes precedence over replaces in go.mod files.  It is
 primarily intended to override conflicting replaces in different workspace
 modules.
 ​
 To determine whether the go command is operating in workspace mode, use
 the "go env GOWORK" command. This will specify the workspace file being
 used.
 ​
 Usage:
 ​
   go work <command> [arguments]
 ​
 The commands are:
 ​
   edit        edit go.work from tools or scripts
   init        initialize workspace file
   sync        sync workspace build list to modules
   use         add modules to workspace file
 ​
 Use "go help work <command>" for more information about a command.

当前的目录结构是:

 ❯ tree
 ├── example
 └── mypkg

初始化 go mod

example 是我们的项目目录, mypkg 是我们开发的包目录

在 example 目录中执行 go mod 初始化命令:

 ❯ go mod init github.com/example
 go: /Users/oo7/Developer/works/example/go.mod already exists

在 mypkg 目录中执行 go mod 初始化命令:

 ❯ go mod init github.com/mypkg
 go: /Users/oo7/Developer/works/mypkg/go.mod already exists

编写 Bar()

在 mypkg 目录中新建文件 demo.go 添加内容:

 package mypkg
 ​
 func Bar() {
   println("this package is mypkg")
 }

Main 函数中调用Bar 函数

我们在 example 中新建 main.go 文件,来调用这个 mypkg 包中的 Bar 函数:

main.go

 package main
 ​
 import (
   "github.com/mypkg"
 )
 ​
 func main() {
   mypkg.Bar()
 }

执行 go mod tidy

我们在 example 目录与 mypkg 目录中执行 go mod tidy 命令, 确保 go.mod 与模块中的源代码匹配。

 ❯ cd example/
 ❯ go mod tidy
 go: finding module for package github.com/mypkg
 github.com/example imports
         github.com/mypkg: cannot find module providing package github.com/mypkg: invalid github.com import path "github.com/mypkg"
 ❯ cd ../mypkg/
 ❯ go mod tidy
 ~/Developer/works/mypkg ❯    

测试代码

我们在 example 目录中执行 go run . 命令,测试我们是否可以正常的函数调用:

 ❯ cd example/
 ❯ go run .
 main.go:4:2: no required module provides package github.com/mypkg; to add it:
         go get github.com/mypkg

从相应结果看 go 并没有找到 mypkg 包,以及 mypkg.Bar() 函数。

使用 go work 初始化

我们在 work 目录中执行 go work init example mypkg

 ❯ go work init example mypkg
 go: /Users/oo7/Developer/works/go.work already exists

执行完成命令后我们发现在 work 的目录下面生成了 go.work 文件

 go 1.20
 ​
 use (
   ./example
   ./mypkg
 )

example 目录中执行 go run . 命令,测试我们是否可以正常的函数调用:

 ❯ go run .
 this package is mypkg

我们看到代码已经可以正常执行了。不在报错找不到包的问题了。

如果我们执行以下命令:

 ❯ GOWORK=off go run main.go
 main.go:4:2: no required module provides package github.com/mypkg; to add it:
         go get github.com/mypkg

GOWORK 设置关闭,同样是报错。

总结

以上我们已经体会到了 go work 的作用,以及与 replace 的对比。

当我们开发完成,应该先提交 mypkg 包到 GitHub,然后在 example 下面执行 go get:

go get github.com/mypkg 即可

目前 VSCode 的 go 插件已经支持 workspace,不需要做什么配置就可以使用 go work。同样使用 goland 的同学也是没有任何问题的。

以上就是详解golang中 work与 module 的区别与联系的详细内容,更多关于golang work与module区别的资料请关注脚本之家其它相关文章!

相关文章

  • Golang中的强大Web框架Fiber详解

    Golang中的强大Web框架Fiber详解

    在不断发展的Web开发领域中,选择正确的框架可以极大地影响项目的效率和成功,介绍一下Fiber,这是一款令人印象深刻的Golang(Go语言)Web框架,在本文中,我们将深入了解Fiber的世界,探讨其独特的特性,并理解为什么它在Go生态系统中引起了如此大的关注
    2023-10-10
  • Golang语言如何高效拼接字符串详解

    Golang语言如何高效拼接字符串详解

    最近在做性能优化,有个函数里面的耗时特别长,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang 里面其实有很多种实现,下面这篇文章主要给大家介绍了关于Golang语言如何高效拼接字符串的相关资料,需要的朋友可以参考下
    2021-11-11
  • Golang中的闭包(Closures)详解

    Golang中的闭包(Closures)详解

    在 Golang 中,闭包是一个引用了作用域之外的变量的函数,Golang 中的匿名函数也被称为闭包,闭包可以被认为是一种特殊类型的匿名函数,所以本文就给大家详细的介绍一下Golang的闭包到底是什么,感兴趣的小伙伴跟着小编一起来看看吧
    2023-07-07
  • golang中字符串MD5生成方式总结

    golang中字符串MD5生成方式总结

    在本篇文章里小编给大家整理的是一篇关于golang中字符串MD5生成方式总结内容,有兴趣的朋友们可以跟着学习参考下。
    2021-07-07
  • Go语言使用singleflight解决缓存击穿

    Go语言使用singleflight解决缓存击穿

    在构建高性能的服务时,缓存是优化数据库压力和提高响应速度的关键技术,但使用缓存也会带来一些问题,其中就包括缓存击穿,下面我们就来看看Go语言中如何使用singleflight解决缓存击穿问题吧
    2024-03-03
  • 详解Golang中的Mutex并发原语

    详解Golang中的Mutex并发原语

    Mutex 是 Go 语言中互斥锁的实现,它是一种同步机制,用于控制多个 goroutine 之间的并发访问。本文将着重介绍 Go 的 Mutex 并发原语,希望对大家有所帮助
    2023-03-03
  • Go字符串操作深入解析

    Go字符串操作深入解析

    这篇文章主要为大家介绍了Go字符串操作深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • golang强制类型转换和类型断言

    golang强制类型转换和类型断言

    这篇文章主要介绍了详情介绍golang类型转换问题,分别由介绍类型断言和类型转换,这两者都是不同的概念,下面文章围绕类型断言和类型转换的相关资料展开文章的详细内容,需要的朋友可以参考以下
    2021-12-12
  • Go语言继承功能使用结构体实现代码重用

    Go语言继承功能使用结构体实现代码重用

    今天我来给大家介绍一下在 Go 语言中如何实现类似于继承的功能,让我们的代码更加简洁和可重用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Go 代码规范错误处理示例经验总结

    Go 代码规范错误处理示例经验总结

    这篇文章主要为大家介绍了Go 代码规范错误处理示例实战经验总结,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08

最新评论