GO语言入门指南2 |青训营

72 阅读5分钟

2.1 错误处理

2.1.1 nil

在Go语言中,如果你声明了一个变量但是没有对它进行赋值操作,那么这个变量就会有一个类型的默认零值。这是每种类型对应的零值:

bool      -> false                              
numbers -> 0                                 
string    -> ""      

pointers -> nil
slices -> nil
maps -> nil
channels -> nil
functions -> nil
interfaces -> nil

2.1.2 errors

  • errors.New() 返回一个error类型
func division(number1, number2 int) (float64, error) {
	if number2 == 0 {
		return 0.0, errors.New("division by zero")  //返回错误,表示除数为0
	}
	
	return float64(number1) / float64(number2), nil
}

panic和recover

  • panic(“语句”) 程序终止运行

panic()触发的宕机发生时,panic后面的代码将不会被执行,但是在panic()函数前面的已经执行过的defer语句依然会在宕机发生时执行defer中的延迟函数

func funcA() {
    fmt.Println("func A")
}
 
func funcB() {
    panic("panic in B")
}
 
func funcC() {
    fmt.Println("func C")
}
 
func funcD() {
    fmt.Println("func D")
}
 
func main() {
    defer funcA()
    defer funcC()
    fmt.Println("this is main")
    funcB()
    defer funcD()
}

运行结果:

this is main
func C
func A
panic: panic in B
 
goroutine 1 [running]:
main.funcB(...)
	/home/wangxm/go_work/src/chapter05/demo.go:12
main.main()
	/home/wangxm/go_work/src/chapter05/demo.go:29 +0xca
exit status 2
  • recover() 防止程序崩溃。

recover捕获到panic时,不会造成整个进程的崩溃,它会从触发panic的位置退出当前函数,然后继续执行后续代码


2.1.4 错误处理实例

import (
	"errors"
	"fmt"
)

type user struct {
	name     string
	password string
}

func findUser(users []user, name string) (v *user, err error) {
	for _, u := range users {
		if u.name == name {
			return &u, nil  //返回u变量地址,和nil错误
		}
	}
	return nil, errors.New("not found") //返回零值用户,和错误
}

func main() {
	u, err := findUser([]user{{"wang", "1024"}}, "wang")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(u.name) // wang

	if u, err := findUser([]user{{"wang", "1024"}}, "li");  //err != nil {
		fmt.Println(err) // not found
		return
	} else {
		fmt.Println(u.name)
	}
}

这个代码片段中,findUser函数的第一个参数是一个[]user类型的切片,表示用户列表。而在调用findUser函数时,传递给它的第一个参数是一个切片字面量[]user{{"wang", "1024"}}。

为什么使用两个大括号{{"wang", "1024"}}呢?这是因为在Go语言中,大括号{}用于创建和初始化结构体类型的值。在这个例子中,user是一个结构体类型,它有两个字段name和password。所以{{"wang", "1024"}}表示创建一个user类型的结构体值,其中name字段的值是"wang",password字段的值是"1024"。

因为findUser函数的第一个参数是一个用户列表,所以需要传递一个切片,即使只有一个用户。所以使用两个大括号{{"wang", "1024"}}来创建一个只包含一个用户的切片

2.2 字符串包

需要引进strings包 (以 a:="hello"为例)

  • 将两个字符串用指定符号相连
    strings.Join([]string{"he","llo"},"_"),结果为“he_llo”
  • 索引字符串
    strings.Index(a, "ll"),结果为2
  • 查询字符串
    strings.Contains(a, "ll"),结果为true
  • 计数字符串
    strings.Count(a, "l"),结果为2
  • 重复字符串
    strings.Repeat(a, 2),结果为“hellohello”
  • 去除字符
    strings.Split("a-b-c", "-"),结果为[a b c]
  • 大小写
    strings.ToLower(a) strings.ToUpper(a)
  • 长度
    len(a)

2.3 格式化

  • %v是通用格式化占位符fmt.Printf("s=%v\n", s)
  • %+v%v的一个变体,它会在打印结构体时,除了打印字段的值外,还会打印字段的名称和冒号。
  • %#v是一种格式化字符串的占位符,用于打印结构体的详细信息,包括字段名和字段值。

2.4 json包

  • json.Marshal()将数据序列化为 JSON 字符串
  • json.MarshalIndent(“数据结构”,“缩进字符串”,“缩进字符数”) 函数用于将 Go 数据结构转换为 JSON 格式的字符串,并且可以按照指定的缩进格式进行格式化
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
buf, err := json.Marshal(a)
fmt.Println(buf)         // [123 34 78 97...]
fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
  • json.Unmarshal() 函数用于将 JSON 数据解析为 Go 语言中的结构体或者其他数据类型
type Student struct {
	// 变量首字母大写才能被解析
	Name string `json:"name"` // name表示在json中Name的字段名
	Age  int    `json:"age"`  //json标签
}

func main() {
	student := Student{
		Name: "韩信",
		Age:  24,
	}
	marshal, _ := json.Marshal(&student)
	s := string(marshal)
	fmt.Println("序列化后:", s) // 序列化后: {"name":"韩信","age":24}

	// 使用Unmarshal反序列化
	json.Unmarshal([]byte(s), &student)
	fmt.Println("反序列化后:", student) // 反序列化后: {韩信 24}
}

2.5 time包

  • time.now():返回当前时间
  • time.date():创建一个新的时间
  • time1.Sub(time2):计算两个时间的之间持续的时间
  • time.Parse(): 解析格式化字符串并返回相应的时间 -time.Unix(): 计算当前时间的unix时间戳 -time.Format():格式化输出时间 -time.Year()/Month()/Day(): 年/月/日...
fmt.Println(time.Now() // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t)                                                  // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05"))                    // 2022-03-27 01:25:36
diff := t2.Sub(t)
fmt.Println(diff)                           // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
	panic(err)
}
fmt.Println(t3 == t)    // true
fmt.Println(now.Unix()) // 1648738080

2.6 strconv包

  • strconv.ParseFloat(字符串, 精度):将字符串转换为浮点数。
  • strconv.ParseInt(字符串, X进制, 位数):将字符串转换为整数。
    • strconv.Atoi("123")
  • strconv.Atoi(字符串):将字符串转换为整数。
    • strconv.Atoi("AAA")

2.7 os包和os/exec包

os包是Go语言标准库中的一个包,提供了与操作系统交互的功能。它包含了处理文件、目录、环境变量、进程等操作的函数和类型。通过os包,我们可以执行文件操作、获取和设置环境变量、处理进程等。

os/exec包也是Go语言标准库中的一个包,用于执行外部命令。它提供了创建和执行外部命令的功能,可以在Go程序中调用其他可执行文件、脚本或系统命令。通过os/exec包,我们可以创建命令对象、设置命令的参数和环境变量、执行命令并获取其输出结果等操作。

  • os.Getenv()获取指定环境变量的值
  • os.Setenv("AA", "BB"): 这个函数设置环境变量AA的值为BB
  • exec.Command(命令名称, 命令所需参数).CombinedOutput()执行命令并返回命令的输出结果和错误信息
  • os.Args 是一个字符串切片,用于获取程序运行时的命令行参数
  • os.Stdin os.Args是一个字符串切片,用于获取程序运行时的命令行参数