详解如何在golang项目开发中创建自己的Module

 更新时间:2023年09月24日 08:42:42   作者:demo007x  
既然我们使用了很多开源的 module为我们的日常开发提供了很多的便捷性,那我们该如何实现自己的 module 来提供给团队中使用,接下小编就给大家介绍一下在golang项目开发如何创建自己的Module,需要的朋友可以参考下

为什么要创建一个 Module?

我们日常开发程序的时候都会引入第三方的 package,使用第三方的 package 的好处是我们可以快速的开发我们的程序的功能,只需要专注我们自己项目的功能,而且第三方的 package 提供了强大的,丰富的功能模块。比如 web 开发框架 ginecho,微服务开发框架 go-microgo-zero;权限控制:casbin,jwt: jwt-gogorm:gorm, 存储:minio 编写命令:cobra, 配置文件解析:viper,数据库:mysql 等等。这些包都是以 module 的形式提供的服务。

在自己的团队内部同样可以构建自己的私有化的 module,工公司内部的其他团队使用。比如我们公司有三个项目组,都有一些共同的项目。所以我们有公共的 module 放到 gitlab 上面提供不同团队的公共使用。同样这样也遵循了软件设计的高内聚低耦合的设计总则。将独立的功能封转为 module

这样做的好处是我们可以只实现一次共享使用,并不需要每个团队中都各自实现,同样也会带啦有好多弊端。

如何实现我们自己的 Module?

既然我们使用了很多开源的 module为我们的日常开发提供了很多的便捷性,那我们该如何实现自己的 module 来提供给团队中使用,甚至可以开放到 gitlab 上面提供给所有人使用(取之于开源,馈与开源)。

通过一下步骤来实现一个其他人可以使用的 module

  • 创建模块:编写一个小模块,其中包含可以从另一个模块调用的函数。
  • 从另一个模块调用您的代码:导入并使用您的新模块。
  • 返回并处理错误: 添加简单的错误处理。
  • 处理切片中的数据(Go 的动态大小数组)。
  • 添加测试程序:使用 Go 的内置单元测试功能来测试您的代码。

创建一个 module 目录

首先创建一个 Go 模块。在模块中,我们可以将一组有用的功能在一个或多个相关包中实现。

Go 代码被分组为 packagepackage 又被分组为modulemodule 中需要指定运行代码所需的依赖项,包括 Go 版本及其所需的其他模块。

1、打开控制台并cd转到工作目录中,并创建目录module/greetings

 mkdir module
 cd module/greetings/

2、go mod init命令初始化模块 。

运行go mod init命令,为其提供模块路径 - 此处使用example.com/greetings. 如果发布模块,则这必须是 Go 工具可以下载您的模块的路径。那将是我们的代码的存储库。

 $ go mod init example.com/greetings

go mod init命令创建一个 go.mod 文件来跟踪代码的依赖项。当我们添加依赖项时,go.mod 文件将列出项目的代码所依赖的版本。这可以保持构建的可重复性,并让我们可以直接控制要使用的模块版本。

3、打开编辑器在greetings创建目录下创建 文件greetings.go并编写代码:

 package greetings
 ​
 import (
   "fmt"
   "math/rand"
 )
 func Hello(name string) string {
   return fmt.Sprintf("嗨,%v。欢迎!", name)
 }

该函数Hello 接受一个name类型为的参数 string。该函数还返回一个string。在Go中,名称以大写字母开头的函数可以被不在同一包中的函数调用。这在 Go 中称为导出名称。

从另一个模块调用您的代码

1、我们在 greeting 的同级目录创建 hello 目录,作为调用者。

 ~/Developer/module
 tree -d
 .
 ├── greetings
 └── hello

2、打开编辑器并创建文件 hello.go 文件。在 hello.go 文件中编写代码:

 import (
   "example.com/greetings"
   "log"
 )
 ​
 func main() {
   message := greetings.Hello("demo007")
   fmt.Println(message)
 }

在文件中声明一个main包。在 Go 中,作为应用程序执行的代码必须位于包中main

导入两个包:example.com/greetingsfmt。 导入 example.com/greetings可以访问该Hello 函数。还可以导入fmt, 以及处理输入和输出文本的函数(例如将文本打印到控制台)。greetings通过调用包的 函数 来获取输出信息。

3、编辑example.com/hello模块以使用本地 example.com/greetings模块。

example.com/greetings 对于生产使用, 可以从其存储库发布模块,Go 工具可以在其中找到它并下载它。但是由于我们尚未发布该模块,因此我们需要调整该模块,以便它可以在本地文件系统上 example.com/hello找到代码example.com/greetings

所以我们使用go mod edit命令编辑example.com/hello 模块,将 Go 工具从其模块路径(模块所在的位置)重定向到本地目录(模块所在的位置)。

在 hello 目录中的命令提示符下,运行以下命令:

 $ go mod edit -replace example.com/greetings=../greetings

该命令指定example.com/greetings应替换为../greetings以便查找依赖项。运行命令后,hello 目录中的 go.mod 文件应包含一条replace的指令。

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

然后我们在命令中 cd hello 的目录中,并执行命令 go mod tidy, 执行完成后我们发现新增加一行 require example.com/greetings v0.0.0-00010101000000-000000000000 并制定了一个版本号.

我们在 hello 中执行运行命令查看:

 go run hello.go
 嗨,demo007。欢迎!

返回并处理错误

处理错误是可靠代码的一个基本特征。下面我们将添加一些代码以从 greetings 模块返回错误,然后在调用者中处理它。

在 greetings/greetings.go 中,修改代码:

 package greetings
 ​
 import (
   "errors"
   "fmt"
   "math/rand"
 )
 ​
 func Hello(name string) (string, error) {
   // 如果没有提供名称,则返回带有错误消息的错误。
   if name == "" {
     return name, errors.New("empty name")
   }
 ​
   // 使用随机格式创建一条消息。
   message := fmt.Sprintf("嗨,%v。欢迎!", name)
   return message, nil
 }

我们修改了 Hello 函数添加了返回值 errorif 语句来检测输入的 name 是否是一个有效的值。如果为空则返回name 和 一个 错误 errors.New("empty name")

hello/hello.go 文件中,处理函数现在返回的错误 Hello以及非错误值。

 package main
 ​
 import (
   "example.com/greetings"
   "fmt"
   "log"
 )
 ​
 func main() {
   message, err := greetings.Hello("demo007")
   if err != nil {
     log.Fatal(err)
   }
   fmt.Println(message)

使用标准库中的函数log package输出错误信息。如果出现错误,可以使用 log包的Fatal来打印错误并停止程序。

在目录中的命令行中hello,运行 hello.go 以确认代码有效

 go run hello.go
 Great to see you, demo007!

处理切片中的数据

我们将使用 Go 切片。切片类似于数组,只不过它的大小会随着添加和删除项目而动态变化。切片是 Go 最有用的类型之一。

我们将添加一个小切片来包含三条问候消息,然后让代码随机返回其中一条消息。

greetings/greetings.go 中,我们修改代码,如下所示。

 package greetings
 ​
 import (
   "errors"
   "fmt"
   "math/rand"
 )
 ​
 func Hello(name string) (string, error) {
   // 如果没有提供名称,则返回带有错误消息的错误。
   if name == "" {
     return name, errors.New("empty name")
   }
 ​
   // 使用随机格式创建一条消息。
   message := fmt.Sprintf(randomFormat(), name)
   return message, nil
 }
 ​
 func randomFormat() string {
   formats := []string{
     "Hi, %v. Welcome!",
     "Great to see you, %v!",
     "Hail, %v! Well met!",
   }
   return formats[rand.Intn(len(formats))]
 }

1、添加一个randomFormat函数,返回随机选择的问候消息格式。 randomFormat以小写字母开头,使其只能被其自己的包中的代码访问(换句话说,它不会被导出)。

2、在 中randomFormat,声明formats具有三种消息格式的切片。声明切片时,您可以在括号中省略其大小,如下所示:[]string。这告诉 Go 切片底层数组的大小可以动态更改。

3、使用该 math/rand 包生成一个随机数,用于从切片中选择一个项目。

4、在 中Hello,调用该randomFormat函数来获取您将返回的消息的格式,然后 name一起使用该格式和值来创建消息。

5、像以前一样返回消息以及错误

hello/hello.go 中,我们修改代码,如下所示:

 package main
 ​
 import (
   "example.com/greetings"
   "fmt"
   "log"
 )
 ​
 func main() {
   message, err := greetings.Hello("demo007x")
   // 如果返回了错误,请将其打印到控制台并退出程序。
   if err != nil {
     log.Fatal(err)
   }
   //如果没有返回错误,请将返回的消息打印到控制台。
   fmt.Println(message)
 }
 ​

我们运行代码看看输出的内容:

 go run hello.go
 Hail, demo007x! Well met!
 ​
 go run hello.go
 Great to see you, demo007x!
 ​
 go run hello.go
 Hi, demo007x. Welcome!

测试 module

以上我们编写了基本的或者说是最简单的 golang module 的程序项目,如何确保我们的程序是无错误的或者是没有 bug 的?最好的办法就是添加 测试程序

在开发过程中测试代码可能会暴露出在您进行更改时出现的错误。

Go 对单元测试的内置支持使我们可以更轻松地进行测试。具体来说,使用命名约定、Go 的testing包和go test命令,可以快速编写和执行测试。

  • 在greetings目录中,创建一个名为greetings_test.go的文件。

    以 _test.go 结尾的文件名告诉go test命令该文件包含测试函数。

  • 在greetings_test.go中,编写以下代码并保存文件:

 package greetings
 ​
 import (
   "regexp"
   "testing"
 )
 ​
 // TestHelloName 调用 greetings.Hello 并传入一个名称,检查返回值是否有效。
 func TestHelloName(t *testing.T) {
   name := "Gladys"
   want := regexp.MustCompile(`\b` + name + `\b`)
   msg, err := Hello("Gladys")
   if !want.MatchString(msg) || err != nil {
     t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
   }
 }
 ​
 // TestHelloEmpty 调用 greetings.Hello 并传入空字符串, 检查是否出现错误。
 func TestHelloEmpty(t *testing.T) {
   msg, err := Hello("")
   if msg != "" || err == nil {
     t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
   }
 }
  • 创建两个测试函数来测试该greetings.Hello 函数。测试函数名称的形式为,其中Name表示有关特定测试的信息。此外,测试函数将指向包的指针作为参数。可以使用此参数的方法来报告和记录测试。

  • 两个测试:

    • TestHelloName调用该Hello函数,传递一个name值,该函数应该能够返回有效的响应消息。如果调用返回错误或意外响应消息(不包含您传入的名称),则可以使用参数t的方法将消息打印到控制台并结束执行Fatalf
    • TestHelloEmpty Hello使用空字符串调用该函数。此测试目的在确认错误处理是否有效。如果调用返回非空字符串或没有错误,则可以使用t参数的Fatalf 方法将消息打印到控制台并结束执行。
  • 在greetings目录下的命令行中,运行命令 go test 执行测试。

 go test -v
 === RUN   TestHelloName
 --- PASS: TestHelloName (0.00s)
 === RUN   TestHelloEmpty
 --- PASS: TestHelloEmpty (0.00s)
 PASS
 ok    example.com/greetings 0.007s
  • 通过测试输出的结果可以看到我们的程序全部都通过了测试。

发布module

以上我们编写了我们的第一个 go module, 并且编写了对应函数的测试程序,然后我们可以将我们的 module 程序提交到 github等系统。其他人就可以通过执行命令 go get example.com/greetingsgreeting 包安装到自己的项目中。

总结:

golang module 给我们提供了灵活的本地开发并测试 module 的机制。我们通过修改 go.mod 文件,通过指令 replace example.com/greetings => ../greetings 来实现本地 module 的开发和测试的全部过程。

以上就是详解golang项目开发如何创建自己的Module的详细内容,更多关于golang创建Module的资料请关注脚本之家其它相关文章!

相关文章

  • Go并发原语之SingleFlight请求合并方法实例

    Go并发原语之SingleFlight请求合并方法实例

    本文我们来学习一下 Go 语言的扩展并发原语:SingleFlight,SingleFlight 的作用是将并发请求合并成一个请求,以减少重复的进程来优化 Go 代码
    2023-12-12
  • go 类型转换方式(interface 类型的转换)

    go 类型转换方式(interface 类型的转换)

    这篇文章主要介绍了go 类型转换方式(interface 类型的转换),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • golang动态创建类的示例代码

    golang动态创建类的示例代码

    这篇文章主要介绍了golang动态创建类的实例代码,本文通过实例代码给大家讲解的非常详细,需要的朋友可以参考下
    2023-06-06
  • Go语言网站使用异步编程和Goroutine提高Web的性能

    Go语言网站使用异步编程和Goroutine提高Web的性能

    作为一门现代化编程语言,Go语言提供了强大的异步编程能力,使得程序员可以以更高效的方式处理并发任务,在Go语言中,使用Goroutine在单个进程中实现多任务并行处理,以及如何使用协程池来进一步提高Web服务器的处理能力,
    2024-01-01
  • 提升Go语言开发效率的小技巧实例(GO语言语法糖)汇总

    提升Go语言开发效率的小技巧实例(GO语言语法糖)汇总

    这篇文章主要介绍了提升Go语言开发效率的小技巧汇总,也就是Go语言的语法糖,掌握好这些可以提高我们的开发效率,需要的朋友可以参考下
    2022-11-11
  • Go设计模式之享元模式讲解和代码示例

    Go设计模式之享元模式讲解和代码示例

    享元是一种结构型设计模式,它允许你在消耗少量内存的情况下支持大量对象,模式通过共享多个对象的部分状态来实现上述功能,换句话来说,享元会将不同对象的相同数据进行缓存以节省内存,本文就将通过代码示例给大家详细介绍一下享元模式
    2023-06-06
  • Go语言panic和recover的用法实例

    Go语言panic和recover的用法实例

    panic()和recover()是Go语言中用于处理错误的两个重要函数,本文主要介绍了Go语言panic和recover的用法实例,panic()用于中止程序并引发panic,而recover()用于捕获panic并恢复程序的执行,感兴趣的可以了解一下
    2024-01-01
  • Go语言对字符串进行SHA1哈希运算的方法

    Go语言对字符串进行SHA1哈希运算的方法

    这篇文章主要介绍了Go语言对字符串进行SHA1哈希运算的方法,实例分析了Go语言针对字符串操作的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • golang协程池模拟实现群发邮件功能

    golang协程池模拟实现群发邮件功能

    这篇文章主要介绍了golang协程池模拟实现群发邮件功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • Go 日志封装实战示例详解

    Go 日志封装实战示例详解

    这篇文章主要为大家介绍了Go 日志封装实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04

最新评论