• Go语言-华山论剑


    目录

    包管理

    主函数和主包

    Go Module

    初始化

    导入第三方包

    常用命令

     Go中的OOP

    结构而不是类

    New() 函数代替构造函数

    Testing

    第一个单元测试


    包管理

    主函数和主包

    每个可执行的 Go 应用程序都必须包含 main 函数。该函数是执行的入口点。主要功能应该驻留在主包中。

    package packagename指定特定源文件属于 package packagename。这应该是每个 go 源文件的第一行。

    我们创建一个名为learnpackage的目录,并在在learnpackage目录中新建main.go文件,并新增以下内容:

    1. package main
    2. import "fmt"
    3. func main() {
    4. fmt.Println("Simple interest calculation")
    5. }

    该行代码package main指定该文件属于主包。import "packagename"语句用于导入现有包。packagename.FunctionName()是调用包中函数的语法。

    在第3行中,我们导入fmt包使用Println功能。这fmt是一个标准包,属于 Go 标准库内置的一部分,

    作为 Go 标准库的一部分内置。主函数的主要内容为打印Simple interest calculation

    Go Module

    Go1.11开始新增了命令go mod来支持Modules的使用。

    初始化

    首先确保在确保在learnpackage目录中。在这个目录中运行以下命令来创建一个名为learnpackage的 go 模块。

    go mod init learnpackage
    

    上面的命令将创建一个名为go.mod. 以下将是该文件的内容。

    module learnpackage go 1.18  
    

    该行module learnpackage指定模块的名称是learnpackage。正如我们之前提到的,learnpackage将是导入此模块内创建的任何包的基本路径。行go 1.18 指定此模块中的文件使用go version 1.18

    这时候我们目录将如下:

    1. ├── learnpackage
    2. │ ├── go.mod
    3. │ ├── main.go

    导入第三方包

    开发中我们经常需要用到第三方包,我们修改 main.go 文件如下:

    1. package main
    2. import (
    3. log "github.com/sirupsen/logrus"
    4. )
    5. func main() {
    6. log.WithFields(log.Fields{
    7. "animal": "walrus",
    8. }).Info("A walrus appears")
    9. }

    第 4 行我们引入了第三方的 log 包。保存好之后,然后执行 go build,再次查看go.mod文件发现多了一些内容:

    1. module learnpackage go 1.18
    2. require github.com/sirupsen/logrus v1.1.1

    这就是引入第三方包。但是通常我们借助 ide 或 其它智能编辑器时,都会自动下载包。

    常用命令

    以上章节,都假设你是一位想学习 golang 编程的新手。 关于 go modules,只使用到了 go mod init 命令。若想看看 go mod 还有哪些功能,使用 go mod help 查看。

    随着你的项目越来越复杂,会引用别人写好的库,这时你会需要 go mod tidy 来帮助管理。

    1. go mod init initialize new module in current directory 在当前目录初始化mod
    2. go mod tidy //拉取缺少的模块,移除不用的模块。
    3. go mod download //下载依赖包
    4. go mod vendor //将依赖复制到vendor下
    5. go mod verify //校验依赖
    6. go list -m -json all //依赖详情
    7. go mod graph //打印模块依赖图
    8. go mod why //解释为什么需要依赖

     Go中的OOP

    结构而不是类

    Go 不提供类,但提供 structs。可以在结构上添加方法。这提供了将数据和对数据进行操作的方法捆绑在一起的行为,类似于一个类。

    让我们从一个例子开始,以便更好地理解。

    我们将在此示例中创建一个自定义包,因为它有助于更好地理解结构如何成为类的有效替代品。

    ~/Documents/里面创建一个子文件夹oop

    让我们初始化oop。 在目录中键入以下命令:

    go mod init oop
    

    在oop里面创建一个子文件夹employee。在employee文件夹中,创建一个名为employee.go的文件 。这时文件结构如下:

    1. ├── Documents
    2. │ └── oop
    3. │ ├── employee
    4. │ │ └── employee.go
    5. │ └── go.mod

    打开 employee.go 文件写入如下代码:

    1. package employee
    2. import (
    3. "fmt"
    4. )
    5. type Employee struct {
    6. FirstName string
    7. LastName string
    8. TotalLeaves int
    9. LeavesTaken int
    10. }
    11. func (e Employee) LeavesRemaining() {
    12. fmt.Printf("%s %s has %d leaves remaining\n", e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken))
    13. }

    在上面的程序中,第一行指定了这个文件属于 employee 包,Employee 结构体在第7行中声明,第14行中名为 LeavesRemaining 的方法被添加到 Employee 结构中。这将计算并显示员工剩余的休假天数。现在,我们有了一个结构体和一个方法,该方法和捆绑在一起的结构体进行操作,类似于class。

    main.go在文件夹内创建一个名为的oop文件。

    现在文件夹结构看起来像:

    1. ├── Documents
    2. │ └── oop
    3. │ ├── employee
    4. │ │ └── employee.go
    5. │ ├── go.mod
    6. │ └── main.go

    main.go内容如下:

    1. package main
    2. import "oop/employee"
    3. func main() {
    4. e := employee.Employee {
    5. FirstName: "Sam",
    6. LastName: "Adolf",
    7. TotalLeaves: 30,
    8. LeavesTaken: 20,
    9. }
    10. e.LeavesRemaining()
    11. }

    我们在第3行导入了 employee 包,在 main 方法中的第20行调用了 employee 结构体的 LeavesRemaining 方法。

    这个程序不能在playground上运行,因为它有一个自定义包。如果你在本地运行这个程序,go install然后发送命令oop,程序将打印输出:

    Sam Adolf has 10 leaves remaining
    

    New() 函数代替构造函数

    Go 不支持构造函数。那我们应该怎么办呢?

    第一步是取消导入Employee结构并创建一个函数New(),该函数将创建一个新的Employee。将employee.go代码替换为以下内容:

    1. package employee
    2. import (
    3. "fmt"
    4. )
    5. type employee struct {
    6. firstName string
    7. lastName string
    8. totalLeaves int
    9. leavesTaken int
    10. }
    11. func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee {
    12. e := employee {firstName, lastName, totalLeave, leavesTaken}
    13. return e
    14. }
    15. func (e employee) LeavesRemaining() {
    16. fmt.Printf("%s %s has %d leaves remaining\n", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
    17. }

    然后将 main.go的内容替换为以下内容:

    1. package main
    2. import "oop/employee"
    3. func main() {
    4. e := employee.New("Sam", "Adolf", 30, 20)
    5. e.LeavesRemaining()
    6. }

    此文件的唯一更改是第 6 行。 我们通过将所需参数传递给New函数创建了一个新员工。

    尽管 Go 不支持类,但可以有效地使用结构来代替类,并且New(parameters)可以使用签名方法代替构造函数。


    Testing

    Go语言中自带有一个轻量级的测试框架 testing 和自带的 go test 命令来实现单元测试和性能测试。在包目录内,以 _test.go 为后缀名的源文件都是 go test 的一部分,而不是 go build 的构建部分。

    要编写一个新的测试,我们必需遵守以下约定:

    • 文件名必须是_test.go结尾的,这样在执行go test的时候才会执行到相应的代码。
    • 必须import testing这个包。
    • 所有的测试用例函数必须是Test开头。
    • 测试用例会按照源代码中写的顺序依次执行。
    • 测试函数TestX()的参数是testing.T,我们可以使用该类型来记录错误或者是测试状态。
    • 测试格式:func TestXxx (t *testing.T),Xxx部分可以为任意的字母数字的组合,但是首字母不能是小写字母[a-z],例如Testintdiv是错误的函数名。
    • 函数中通过调用testing.TErrorErrorfFailNowFatalFatalIf方法,说明测试不通过,调用Log方法用来记录测试的信息。

    第一个单元测试

    现在我们新建一个目录以及文件,结构如下:

    1. ├── Documents
    2. │ └── util.go
    3. │ ├── util_test.go

    util.go 内容如下:

    1. package util
    2. func Int(a, b int) int {
    3. if a > b {
    4. return a
    5. }
    6. return b
    7. }

    util_test.go 内容如下:

    1. package util
    2. import "testing"
    3. func TestInt(t *testing.T) {
    4. sumA := Int(1, 2)
    5. if sumA != 2 {
    6. t.Errorf("exp: %d, got: %d", 2, sumA)
    7. }
    8. }

    执行 go test, 打印结果如下:

    PASSok      code/util        0.001s
    

    以上就是一个简单的单元测试示例。

    特别推荐通过测试驱动来学习 Go 语言。能让你更好的理解 Go 语言。

  • 相关阅读:
    Python笔记三之闭包与装饰器
    【ROS机器人】Autolabor Pro RTK室外厘米级导航
    区块链技术与应用 - 学习笔记2【密码学基础】
    全网营销如何落地?全网营销的途径有哪些?
    Java设计模式——工厂模式讲解以及在JDK中源码分析
    Linux 部署 MinIO 分布式对象存储 & 配置为 typora 图床
    POSIX 标准-信号量sem_t
    GIT学习之路
    学用 DevChat 的 VSCode 插件,体验AI智能编程工具 (一)
    多线程处理大批量数据操作
  • 原文地址:https://blog.csdn.net/mooczhimahu/article/details/126451973