# go.workspace-skeleton **Repository Path**: zinface/go.workspace-skeleton ## Basic Information - **Project Name**: go.workspace-skeleton - **Description**: 分析 Go Work 工作空间的主体结构预览 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-12-23 - **Last Updated**: 2023-01-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Go Work 工作空间骨架预览 - 一个基本的 go 工作空间主体结构 ``` . ├── docs │ └── go-work-help.md ├── hello │ ├── go.mod │ └── main.go ├── say │ ├── go.mod │ └── say.go ├── go.work └── README.md 2 directories, 7 files ``` - 来源于项目主体结构的说明 ```shell # 创建并进入临时目录 cd `mktemp -d` # 在本目录中初始化为 go workspace # 生成一个 go.work 文件用来标识 go 的工作空间 go work init; # 创建两个模块(say 和 hello),作为 workspace 中的模块 mkdir say hello; # 进入 say 模块中初始化为 say 项目 cd say; go mod init say; cd ..; # 进入 hello 模块中初始化为 hello 项目 cd hello; go mod init hello; cd ..; ``` - 来源于 go 的工作空间 的说明 ```go // go work 是 1.18版本随带的新特性 // 这个特性为 go 项目带来了多模块开发的全新方式。 // 在以前我们基于自己编写的库(也叫模块)进行开发时,常常会为自己的库进行改进。 // 例如在编写基于 go-gin 框架时,我们会使用一些 gin 的扩展库来提升逻辑处理效率, // 同时我们会为自己定制或开发一个新的 gin 扩展库来单独维护我们的接口内容管理方式。 // 例如: 为 gin 框架编写一个用于上传文件时接收的通用处理操作。 // 我们会创建其 gin-external-fileupload 项目,专门用于处理上传的文件进行处理。 // 首先按照之前所说的,我们基于已有的模块 gin-external-fileupload 进行使用。 // 例如使用命令 go get github.com/user/gin-external-fileupload 获取此库。 // 我们即可在项目中开始使用,前提是此前该库已经进入了代码仓库。 // 接着我们在编写 gin 框架的上传文件处理时,发现 gin-external-fileupload 库 // 并不满足当前的使用需求,并且需要做一些调整或扩展。 // 由于我们无法直接更改 gin-external-fileupload 模块的源代码,必须拉取到本地 // 再进行更改,所以我们在某个位置例如桌面上存放这个库的源代码。 // 例如: // /home/user/Desktop/gin-external-fileupload // // 然后在我们项目的 go.mod 中使用 replace 指定 // replace gitee.com/user/gin-external-fileupload => "/home/user/Desktop/gin-external-fileupload" // ^ 这是此库的原始位置 ^ 我们重新指定为本地 // 最后,我们可以通过更改本地的库代码,并在项目中使用。 // 这里需要注意的是,添加了 replace 内容的 go.mod 文件一定不要提交到仓库,否则 // 会引发非常严重的部署问题,并且本地库新的内容也需要同时提交到代码仓库。 // 这是在 1.18 之前到现在也许还有人在用的扩建方式 ``` 先来个例子,这是在使用 1.18 之前的开发模式 ```go // 这是个简单的基于 gin 框架的文件管理器 // https://gitee.com/zinface/go.gin-filemanager // 例如目前我准备了一个基于 go-gin 框架的一个示例,此时我将获取此前编写的 // gin-filemanager 库(这一个一包含可存储上传文件与文件管理的库): // go get gitee.com/zinface/go.gin-filemanager // // 库中包含一个定义的 FileManager 的 struct 声明 // // 文件管理器 type FileManager struct { BasePath string } // // 然后在我的示例代码中使用: // import filemanager "gitee.com/zinface/go.gin-filemanager" var fm *filemanager.FileManager func init() { fm = filemanager.NewFileManager("./static/upload") fmt.Println(fm.BasePath) } // 我可以在 go run 运行时打印 BasePath 的内容。 // 此时,我认为应该给 BasePath 包装一个 GetBasePath() 的函数 // 我就必须获取此库的源代码,并在示例项目的 go.mod 中添加一行 replace 内容 // 来重定向在 import 此库时引用的位置 // replace gitee.com/zinface/go.gin-filemanager => /home/zinface/Desktop/go.gin-filemanager // // 最后我们在本地为 FileManager 增加一个函数定义 // func (fm *FileManager) GetBasePath() string { return fm.BasePath } // // 回到我们的示例项目中就可以将 // fmt.Println(fm.BasePath) // 替换以上或添加以下内容 fmt.Println(fm.GetBasePath()) // // 最后在执行 go run 时即可打印 BasePath 的内容 ``` - 来源于 go.work 的说明 ```go go 1.18 // 在工作空间中的其它模块中可以发现此处声明的模块(使用 use 即被可见) // 例如: 在 hello 模块中即可开始引入 say 模块的所有内容 use say ``` - 使用 go 1.18 版本后的工作空间来处理之前的例子 - 先来个主体结构,参考 ```shell /tmp/tmp.cFPlrwkhiJ ├── base-gin # 我们的项目 │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── Makefile ├── go.gin-filemanager # 被依赖的 gin-filemanager │ ├── examples │ │ └── simple.go │ ├── filemanager.go │ ├── go.mod │ ├── go.sum │ ├── LICENSE.txt │ ├── meta.go │ └── README.md ├── go.work # 工作区标志文件 └── static └── upload ``` 对此例子进行的说明 ```go // 将一个目录作为 go 的工作空间,这个目录我们将它当是一个多模块的工作区。 // // 大体步骤是: // 1. 使用 go work init 来生成 go.work 文件以将此目录当作工作空间。 // 2. 添加 base-gin 示例项目,来作为一个基于 gin 框架的起始示例。 // 3. 使用 git clone https://gitee.com/zinface/go.gin-filemanager // 来获取基于 gin 的扩展库源代码 // 4. 在 go.work 文件中添加以下内容 // 也可使用 go work use ./base-gin ./go.gin-filemanager 命令添加 use ( ./base-gin ./go.gin-filemanager ) // 这是个简单的基于 gin 框架的文件管理器 // https://gitee.com/zinface/go.gin-filemanager // // 例如目前我准备了一个基于 go-gin 框架的一个示例,此时我将获取此前编写的 // gin-filemanager 库(这一个一包含可存储上传文件与文件管理的库): // // 库中包含一个定义的 FileManager 的 struct 声明 // // 文件管理器 type FileManager struct { BasePath string } // // 然后在我的示例代码中使用: // import filemanager "gitee.com/zinface/go.gin-filemanager" var fm *filemanager.FileManager func init() { fm = filemanager.NewFileManager("./static/upload") fmt.Println(fm.BasePath) } // 我可以在 go run 运行时打印 BasePath 的内容。 // 此时,我认为应该给 BasePath 包装一个 GetBasePath() 的函数 // 那么在 go 的工作区下,我们可以直接修改这个扩展库的源代码 // // 直接为 FileManager 增加一个函数定义 // func (fm *FileManager) GetBasePath() string { return fm.BasePath } // // 回到我们的示例项目中就可以将 fmt.Println(fm.BasePath) // 替换以上或添加以下内容 fmt.Println(fm.GetBasePath()) // // 最后在执行 go run 时即可打印 BasePath 的内容 ``` - 最后说一些有关工作区的预览 ```go // 在使用 go work 进行工作区化管理项目后,我们省去了 replace 这个麻烦。 // 同时也避免了 go.mod 中增加 replace 后可能会因为不小心 commit 到仓库 // 而产生破坏性的生产问题。 // 现在,说到工作区以及 go.work 文件,它们应该是存储在本地的内容,不应该被 // 提交进仓库。 // 如果你将 go.work 或工作区本身提交进了仓库,这个仓库也许就没有办法再使用 // go get 的方式用于获取远端的依赖。 // 基于工作区的构建,它带来了强大的项目扩展与更方便的扩展维护能力,也不再因为 // 不能方便修改你的依赖库而产生烦恼。 ```