这篇文章主要用于说明Go环境搭建,且以hello world为例进行具体说明。
环境
系统: CentOS 7.7
Go版本: go1.16.6
安装
下载并解压
wget https://golang.google.cn/dl/go1.16.6.linux-amd64.tar.gz
tar -C /usr/local -xzf go1.16.6.linux-amd64.tar.gz
配置
我比较习惯在/etc/profile.d目录创建专用的shell文件,比如go.sh用于保存GO相关的环境变量
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/usr/work/
GOPATH通常是GO项目的路径,在GO11之前会经常用到。
GO同样需要设置代理来加速依赖下载,根据go的版本不同设置方式有区别,当前go1.16可以采用下面方式:
go env -w GOPROXY=https://goproxy.cn,direct
从Go1.11开始,Go允许在$GOPATH/src之外的任何目录通过go mod创建项目,而go module就是go 11引入的新特性,它主要有三个属性值:
- GO111MODULE=off: 无模块支持,go会从GOPATH和vendor文件寻找包
- GO111MODULE=on: 模块支持,go会忽略GOPATH和vendor文件夹,只根据go.mod下载依赖
- GO111MODULE=auto:在项目根目录存在go.mod文件,开启模块支持
设置模块支持
go env -w GO111MODULE=on
简单示例
hello world
创建项目
mkdir hello
cd hello
初始化项目
go mod init example/hello
创建代码文件hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
运行代码
$ go run .
Hello, World!
引入依赖包
上面的hello world,将项目的初始化、构建、运行的流程做了简单描述,但是还没有用到依赖包。这里按照go官方文档说明,引入依赖包rsc.io/quote
在上面的hello.go文件中进行改动
package main
import "fmt"
import "rsc.io/quote"
func main() {
fmt.Println(quote.Go())
}
由于引入了新的包,需要执行
go mod tidy
执行完之后,go.mod和go.sum文件会发生变化
运行代码
go run .
vscode debug调试
如果需要vscode debug调试go程序,需要安装go插件,同时需要安装golang.org/x/tools/gopls
自定义Module
创建Module
创建项目目录greetings
mkdir greetings
cd greetings
初始化项目
go mod init example.com/greetings
代码文件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
}
引用Module
创建项目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没有发布,需要修改example.com/hello以便获取greetings的位置
go mod edit -replace example.com/greetings=../greetings
同步example.com/hello模块依赖
go mod tidy
在go.mod中会为example.com/greetings预设版本号,此时可以修改为自定义的版本号
require example.com/greetings v1.0.0
运行项目
go run .
复杂一些
处理Error
处理错误是代码健壮性的一个重要体现。
在greetings/greetings.go中增加错误处理逻辑
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
}
修改hello/hello.go
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/greetings.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))]
}
修改hello/hello.go
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)
}
运行项目
go run .
为多个人返回问候
增加遍历逻辑,修改greetings/greetings.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
}
// Hellos returns a map that associates each of the named people
// with a greeting message.
func Hellos(names []string) (map[string]string, error) {
// A map to associate names with messages.
messages := make(map[string]string)
// Loop through the received slice of names, calling
// the Hello function to get a message for each name.
for _, name := range names {
message, err := Hello(name)
if err != nil {
return nil, err
}
// In the map, associate the retrieved message with
// the name.
messages[name] = message
}
return messages, 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 one of the message formats selected at random.
return formats[rand.Intn(len(formats))]
}
修改hello/hello.go
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)
// A slice of names.
names := []string{"Gladys", "Samantha", "Darrin"}
// Request greeting messages for the names.
messages, err := greetings.Hellos(names)
if err != nil {
log.Fatal(err)
}
// If no error was returned, print the returned map of
// messages to the console.
fmt.Println(messages)
}
运行项目
go run .
代码测试
在greetings目录,创建测试文件greetings_test.go
package greetings
import (
"regexp"
"testing"
)
// TestHelloName calls greetings.Hello with a name, checking
// for a valid return value.
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 calls greetings.Hello with an empty string,
// checking for an error.
func TestHelloEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}
可以直接在vscode进行测试
或者是执行命令
go test -v
项目构建
在上面主要使用的命令是go run .运行项目,这里熟悉下其他的命令。
构建项目
go build
./hello
可以通过go list命令查看安装路径,执行之后发现在GOPATH
go list -f '{{ .Target }}'
也可以自定义安装路径
go env -w GOBIN=/usr/work/go
此时如果执行命令go install,则会在/usr/work/go看到生成的hello