目录
每个可执行的 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 语言。