目录
包管理
主函数和主包
Go Module
初始化
导入第三方包
常用命令
Go中的OOP
结构而不是类
New() 函数代替构造函数
Testing
第一个单元测试
每个可执行的 Go 应用程序都必须包含 main 函数。该函数是执行的入口点。主要功能应该驻留在主包中。
package packagename
指定特定源文件属于 package packagename
。这应该是每个 go 源文件的第一行。
我们创建一个名为learnpackage
的目录,并在在learnpackage
目录中新建main.go
文件,并新增以下内容:
package main
import "fmt"
func main() {
fmt.Println("Simple interest calculation")
}
该行代码package main
指定该文件属于主包。import "packagename"
语句用于导入现有包。packagename.FunctionName()
是调用包中函数的语法。
在第3行中,我们导入fmt
包使用Println
功能。这fmt
是一个标准包,属于 Go 标准库内置的一部分,
作为 Go 标准库的一部分内置。主函数的主要内容为打印Simple interest calculation
。
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
。
这时候我们目录将如下:
├── learnpackage
│ ├── go.mod
│ ├── main.go
│
开发中我们经常需要用到第三方包,我们修改 main.go
文件如下:
package main
import (
log "github.com/sirupsen/logrus"
)
func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}
第 4 行我们引入了第三方的 log 包。保存好之后,然后执行 go build
,再次查看go.mod文件发现多了一些内容:
module learnpackage go 1.18
require github.com/sirupsen/logrus v1.1.1
这就是引入第三方包。但是通常我们借助 ide 或 其它智能编辑器时,都会自动下载包。
以上章节,都假设你是一位想学习 golang 编程的新手。 关于 go modules,只使用到了 go mod init
命令。若想看看 go mod
还有哪些功能,使用 go mod help
查看。
随着你的项目越来越复杂,会引用别人写好的库,这时你会需要 go mod tidy
来帮助管理。
go mod init initialize new module in current directory 在当前目录初始化mod
go mod tidy //拉取缺少的模块,移除不用的模块。
go mod download //下载依赖包
go mod vendor //将依赖复制到vendor下
go mod verify //校验依赖
go list -m -json all //依赖详情
go mod graph //打印模块依赖图
go mod why //解释为什么需要依赖
Go 不提供类,但提供 structs。可以在结构上添加方法。这提供了将数据和对数据进行操作的方法捆绑在一起的行为,类似于一个类。
让我们从一个例子开始,以便更好地理解。
我们将在此示例中创建一个自定义包,因为它有助于更好地理解结构如何成为类的有效替代品。
在~/Documents/
里面创建一个子文件夹oop
。
让我们初始化oop
。 在目录中键入以下命令:
go mod init oop
在oop里面创建一个子文件夹employee。在employee文件夹中,创建一个名为employee.go的文件 。这时文件结构如下:
├── Documents
│ └── oop
│ ├── employee
│ │ └── employee.go
│ └── go.mod
打开 employee.go
文件写入如下代码:
package employee
import (
"fmt"
)
type Employee struct {
FirstName string
LastName string
TotalLeaves int
LeavesTaken int
}
func (e Employee) LeavesRemaining() {
fmt.Printf("%s %s has %d leaves remaining\n", e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken))
}
在上面的程序中,第一行指定了这个文件属于 employee 包,Employee 结构体在第7行中声明,第14行中名为 LeavesRemaining 的方法被添加到 Employee 结构中。这将计算并显示员工剩余的休假天数。现在,我们有了一个结构体和一个方法,该方法和捆绑在一起的结构体进行操作,类似于class。
main.go在文件夹内创建一个名为的oop文件。
现在文件夹结构看起来像:
├── Documents
│ └── oop
│ ├── employee
│ │ └── employee.go
│ ├── go.mod
│ └── main.go
main.go
内容如下:
package main
import "oop/employee"
func main() {
e := employee.Employee {
FirstName: "Sam",
LastName: "Adolf",
TotalLeaves: 30,
LeavesTaken: 20,
}
e.LeavesRemaining()
}
我们在第3行导入了 employee 包,在 main 方法中的第20行调用了 employee 结构体的 LeavesRemaining 方法。
这个程序不能在playground上运行,因为它有一个自定义包。如果你在本地运行这个程序,go install
然后发送命令oop
,程序将打印输出:
Sam Adolf has 10 leaves remaining
Go 不支持构造函数。那我们应该怎么办呢?
第一步是取消导入Employee
结构并创建一个函数New()
,该函数将创建一个新的Employee
。将employee.go
代码替换为以下内容:
package employee
import (
"fmt"
)
type employee struct {
firstName string
lastName string
totalLeaves int
leavesTaken int
}
func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee {
e := employee {firstName, lastName, totalLeave, leavesTaken}
return e
}
func (e employee) LeavesRemaining() {
fmt.Printf("%s %s has %d leaves remaining\n", e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
}
然后将 main.go
的内容替换为以下内容:
package main
import "oop/employee"
func main() {
e := employee.New("Sam", "Adolf", 30, 20)
e.LeavesRemaining()
}
此文件的唯一更改是第 6 行。 我们通过将所需参数传递给New函数创建了一个新员工。
尽管 Go 不支持类,但可以有效地使用结构来代替类,并且New(parameters)可以使用签名方法代替构造函数。
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.T
的Error
, Errorf
, FailNow
, Fatal
, FatalIf
方法,说明测试不通过,调用Log
方法用来记录测试的信息。现在我们新建一个目录以及文件,结构如下:
├── Documents
│ └── util.go
│ ├── util_test.go
│
util.go
内容如下:
package util
func Int(a, b int) int {
if a > b {
return a
}
return b
}
util_test.go
内容如下:
package util
import "testing"
func TestInt(t *testing.T) {
sumA := Int(1, 2)
if sumA != 2 {
t.Errorf("exp: %d, got: %d", 2, sumA)
}
}
执行 go test
, 打印结果如下:
PASSok code/util 0.001s
以上就是一个简单的单元测试示例。
特别推荐通过测试驱动来学习 Go 语言。能让你更好的理解 Go 语言。