Go语言基础语法(二) | 青训营笔记

84 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

一门语言的基础是极为重要的,因此我将再用一篇文章来记录自己学习Go语言基础语法的内容。在前一篇笔记的基础上,我们在读代码时将视线移出函数来看Go语言包。

在读代码示例时会发现,每个源代码的第一行都是package pacakgeName 语句。

Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案。Go 语言的入口 main() 函数所在的包(package)叫 main,main 包想要引用别的代码,必须同样以包的方式进行引用,即import``"包的路径"语句。Go语言中为我们提供了很多内置包,如 fmt、strings、time 等,本文主要介绍的便是一些在读代码的过程中发现的常用内置包。

fmt

fmt 包实现了格式化的标准输入输出,这与C语言中的 printf 和 scanf 类似。其中fmt.Printf() 和 fmt.Println() 是开发者使用最为频繁的函数。

一些格式化短语如下:

  • %v:默认格式的值
  • %+v:增加字段名
  • %#v:Go样式的值表达

因为Go语言可以自动推导变量类型,所以变量格式化时都可以用v代表。

errors

errors包是Go语言错误处理包,其对外暴露了四个方法:

func As(err erros, target any) bool

func Is(err, target error) bool

func New(text string) error

func Unwrap(err error) error

  • As(err errors, target any) bool

As 方法的作用是在第一个参数 err 的调用链中寻找和第二个参数 target 类型相同的的错误,并把找到的第一个 err 的值赋给 target ,然后返回 true;如果没有找到则返回 false。

  • Is(err errors, target any) bool

相比较于 As 方法,Is 只判断第一个参数 err 的调用链中是否存在和第二个参数 target 类型相同的的错误,存在则返回 true,否则返回 false。

  • New(text string) error

New 方法返回 error 类型,同时指定文本内容为传入的 text 值。

注意:New 方法每次返回的是指针地址,每次调用返回的都是不同的地址,所以尽管两个error指定文本内容是相同的,在比较时它们也是不相等的,如下所示:

package main

import (
 "errors"
 "fmt"
)

func main() {
 
 err1 := errors.New("I am an error.")
 err2 := errors.New("I am an error.")

 fmt.Println(err1 == err2) // false
}
  • Unwrap(err error) error

Unwrap方法返回error类型,用于忽略对于错误信息进行的扩展,如下所示:

package main
import (    "errors"    "fmt")func main() {    err1 := errors.New("I am err1.")    err2 := fmt.Errorf("I am err2 , %w", err1) // 通过 %w 可以生成一个 Wrapping error    fmt.Println(err2)                // I am err2 , I am err1.    fmt.Println(errors.Unwrap(err2)) // I am err1.}

strings

strings 包主要是处理字符串的一些函数集合,包括合并、查找、分割、比较、后缀检查、索引、大小写处理等等。

package mainimport (    "fmt"    "strings")func main() {    a := "hello"    fmt.Println(strings.Contains(a, "ll"))                // true    fmt.Println(strings.Count(a, "l"))                    // 2    fmt.Println(strings.HasPrefix(a, "he"))               // true    fmt.Println(strings.HasSuffix(a, "llo"))              // true    fmt.Println(strings.Index(a, "ll"))                   // 2    fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo    fmt.Println(strings.Repeat(a, 2))                     // hellohello    fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo    fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]    fmt.Println(strings.ToLower(a))                       // hello    fmt.Println(strings.ToUpper(a))                       // HELLO    fmt.Println(len(a))                                   // 5    b := "你好"    fmt.Println(len(b)) // 6}

注意:一个汉字可能占多个字符。

encoding/json

JSON 目前广泛用做网络程序中的通信格式。encoding/json 包提供了对 JSON 的基本支持,比如json.marshal()实现从一个对象序列化为 JSON 字符串,或者json.Unmarshal()实现从 JSON 字符串反序列化出一个具体的对象等。

time

时间和日期是开发中经常会用到的,Go语言中的 time 包提供了时间显示和测量等所用的函数。

  • time.Now() 

获取当前的时间对象,然后通过事件对象来获取当前的时间信息,如下所示:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now() //获取当前时间
    fmt.Printf("current time:%v\n", now)
    year := now.Year()     //年
    month := now.Month()   //月
    day := now.Day()       //日
    hour := now.Hour()     //小时
    minute := now.Minute() //分钟
    second := now.Second() //秒
    weekday := now.Weekday().String() //星期几
    fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
  • now.Unix()【now为存储时间点的变量】和time.Unix()

now.Unix()获取时间戳,时间戳是自 1970 年 1 月 1 日(08:00:00GMT)至当前时间的总毫秒数,常在编程中用到。

time.Unix()可将时间戳转为时间格式

  • 时间操作函数

某个时间+时间间隔:func (t Time) Add(d Duration) Time

求两个时间之间的差值:func (t Time) Sub(u Time) Duration

判断两个时间是否相同:func (t Time) Equal(u Time) bool

判断一个时间点是否在另一个时间点之前:func (t Time) Before(u Time) bool

判断一个时间点是否在另一个时间点之后:func (t Time) After(u Time) bool

  • 定时器

使用 time.Tick(时间间隔) 可以设置定时器

  • 时间格式化

时间类型有一个自带的 Format 方法进行格式化,需要注意的是Go语言中格式化时间模板不是常见的Y-m-d H:M:S 而是使用Go语言的诞生时间 2006 年 1 月 2 号 15 点 04 分 05 秒

  • 解析字符串格式的时间

func Parse(layout, value string) (Time, error)func ParseInLocation(layout, value string, loc *Location) (Time, error)可以解析一个格式化的时间字符串并返回它代表的时间。

strconv

strconv 包提供了strconv.ParseFloat()strconv.ParseInt()解析字符串,strconv.Atoi()将字符串转换成十进制数字,strconv.itoA()将数字转换为字符串,该包包含了很多此类功能。

os

os包可用于获取进程信息os.Args可获取参数,第一个成员代表二进制自身的名字。os.Getenv()os.Setenv()可用于获取和设置环境变量。

总结

合理利用语言所提供的丰富的内置包可以使得开发者的效率大大提高,但与此同时,在引用包的时候也要注意一些规则,例如在阅读课外资料时我发现引用包时可能会出现循环引用的问题,这表明包不能随意引入造成负担甚至错误,因此我们需要充分了解各类常见包,使用陌生的包之前要对其进行了解,最后根据我们的代码结构来进行选择和引用。