一篇关于函数、错误处理、数组、映射、单元测试和编译的短篇介绍。
这里是关于Go语言的一些基本特性介绍的第一部分。如果你是刚开始接触Go,请先看一下这里;这里所跳转的页面会介绍关于go命令、Go模块和一些很简单的Go代码。
在这篇文章里你会创建两个模块。第一个是可以被其他库或者应用程序所导入的库模块。第二个是导入了第一个库的应用程序模块。
下面一系列文本将会介绍七个简短的篇章,而每个篇章分别介绍了一个不同的Go语言的内容。
我们从创建一个Go模块开始。在一个模块中,你会在一个函数单独且有实际应用的部分使用一个或多个相关联的包。比如,你创建了一个包含了多个金融分析函数的包的模块,从而当别人可以引用你写过的成果来写金融相关的程序。更多关于开发模块的信息可以点击这里。
Go代码分类组合成包,而包又分类组合成模块。你的模块里需要说明执行你的代码所需要的依赖,其中包括Go的版本和其他所需要的模块。
当你添加或者修改了你的模块功能,这个时候你需要对你的模块发布一个新的版本。这样子的话,当开发者在把自己的代码部署到生产环境的时候,他们可以对引入了你模块函数的部分导入最新的包并执行新版本的测试。
如果是Linux和Mac:
cd
如果是Windows:
cd %HOMEPATH%
mkdir greetings
cd greetings
执行go mod init命令来定义你的模块路径:在这里我们使用example.com/greetings这个路径。如果你发布了一个模块,那么这个路径必须是Go的工具链可以下载得到的路径,比如可以是你的代码仓库地址。
go mod init example.com/greetings
go mod init命令创建了一个go.mod文件,从而可以追踪到你代码中的依赖。到目前为止,这个go.mod文件只会包含你的模块名称和你代码所支持的Go的版本。但当你添加依赖的时候,go.mod文件会列出你代码所需要的依赖版本。这样子的话,就能让代码重复编译和直接管理使用需要用到的模块版本。
4. 在你的代码编译器中,在你写代码的文件夹下创建一个greetings.go文件。
5. 粘贴下面代码到greetings.go文件中并保存。
package greetings
import "fmt"
// Hello returns a greeting for the named person.
func Hello(name string) string {
// Return a greeting that embeds the name in a message.
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}
这是你模块里的第一段代码。它会为所需要的调用方返回一段问候。你会在下一步写一段代码来调用这个方法。
在这段代码里,你做了以下工作:
var message string
message = fmt.Sprintf("Hi, %v.Welcome!", name)
下一步,我们将会从另外一个模块调用这个方法。
在上面,你已经创建了一个greetings模块。在这个篇章里,你将会写一段代码并引用你刚刚创建的模块里的Hello方法。
比如,如果你当前路径在greetings文件夹里,那么应该使用下面命令。
cd ..
mkdir hello
cd hello
go mod init example.com/hello
为了完成这件事,我们把下面代码粘贴进hello.go里面。
package main
import (
"fmt"
"example.com/greetings"
)
func main() {
// Get a greeting message and print it.
message := greetings.Hello("Gladys")
fmt.Println(message)
}
在这段代码里,你做了以下工作:
在生产环境中使用的时候,你需要把example.com/greetings模块发布到Go的工具链能找到并下载到的仓库中(模块路径需要反映其发布位置)。现在的话,因为你还没有发布这个模块,你需要调整一下example.com\hello模块从而让它能从你的本地文件系统中找到example.com\greetings代码。
为了实现这个功能,我们使用go mod edit命令去配置example.com/hello模块,使得Go工具链把依赖的路径重定向到本地文件夹。
go mod edit -replace example.com/greetings=../greetings
为了定位依赖,这个命令把example.com/greetings替换成…/greetings.当你运行这个命令后,hello文件夹里的go.mod文件应该会包含一条替换的描述:
module example.com/hello
go 1.16
replace example.com/greetings => ../greetings
go mod tidy
在命令执行完之后,example.com/hello模块的go.mod文件应该看起来是这样子的:
module example.com/hello
go 1.16
replace example.com/greetings => ../greetings
require example.com/greetings v0.0.0-00010101000000-000000000000
go mod tidy命令找到在本地的greetings文件夹里面的代码,然后添加一条require描述来识别example.com/hello依赖于example.com/greetings。你会在hello.go导入greetings包时创建这个依赖关系。
跟在模块路径后面的数字是一个伪版本号–这是一段并不存在于相关模块里的版本数字。
如果是为了查询一个发布了的模块,go.mod文件会特别地删掉替换描述和在末尾使用带上设置好的版本号的依赖描述。
require example.com/greetings v1.1.0
恭喜!你已经写了两个功能模块。
在下个篇章,你将会为你的代码加上一些错误处理。
错误处理是健壮的代码一项基本特性。在这个篇章里,你将会在greetings模块里添加一点可以返回错误的代码,然后在调用方处理这个错误。
package greetings
import (
"errors"
"fmt"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value that embeds the name
// in a greeting message.
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message, nil
}
在这段代码里,你做了以下工作:
package main
import (
"fmt"
"log"
"example.com/greetings"
)
func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("greetings: ")
log.SetFlags(0)
// Request a greeting message.
message, err := greetings.Hello("")
// If an error was returned, print it to the console and
// exit the program.
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned message
// to the console.
fmt.Println(message)
}
在这段代码里,你做了以下工作:
go run .
greetings: empty name
exit status 1
这是Go里面通用的错误处理方法:把报错作为值回传让调用方可以进行检查。
接下来,你将会使用Go切片返回一段随机选择的问候。
在这个篇章中,你会通过修改你的代码来实现返回我们预先设置后的其中一段问候,而不再是返回单一问候了。
为了做到上述操作,你将会使用一个Go的切片。切片除了当你添加或移除元素的时候他的大小可以动态修改外,其余的特性都很像一个数组。切片是Go最为有用的特性之一。
你将会添加一个包含了三段问候的话语信息小切片,然后让你的代码随机返回其一。
package greetings
import (
"errors"
"fmt"
"math/rand"
"time"
)
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("empty name")
}
// Create a message using a random format.
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}
// init sets initial values for variables used in the function.
func init() {
rand.Seed(time.Now().UnixNano())
}
// randomFormat returns one of a set of greeting messages. The returned
// message is selected at random.
func randomFormat() string {
// A slice of message formats.
formats := []string{
"Hi, %v. Welcome!",
"Great to see you, %v!",
"Hail, %v! Well met!",
}
// Return a randomly selected message format by specifying
// a random index for the slice of formats.
return formats[rand.Intn(len(formats))]
}
在这段代码里,你做了以下事情:
package main
import (
"fmt"
"log"
"example.com/greetings"
)
func main() {
// Set properties of the predefined Logger, including
// the log entry prefix and a flag to disable printing
// the time, source file, and line number.
log.SetPrefix("greetings: ")
log.SetFlags(0)
// Request a greeting message.
message, err := greetings.Hello("Gladys")
// If an error was returned, print it to the console and
// exit the program.
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned message
// to the console.
fmt.Println(message)
}
3.在命令行的hello文件夹下,运行hello.go来确认代码可以成功运行。多运行几次来观察问候语句的变化。
$ go run .
Great to see you, Gladys!
$ go run .
Hi, Gladys. Welcome!
$ go run .
Hail, Gladys! Well met!
下一节,你将会使用一个slice来问候多个人。