Go语言基础语法 - 标准库

75 阅读14分钟

标准库

字符串操作

在 Golang 中,字符串操作是通过标准库 strings包提供的各种工具函数来实现的。这些函数可以帮助我们方便地进行字符串的查找、替换、连接等操作。

package main

import (
    "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
}

strings.Contains

fmt.Println(strings.Contains(a, "ll")) // true
  • 功能: 判断字符串 a 是否包含子字符串 "ll"
  • 返回值: 返回布尔值,表示是否包含。

strings.Count

fmt.Println(strings.Count(a, "l")) // 2
  • 功能: 统计字符串 a 中子字符串 "l" 出现的次数。
  • 返回值: 返回整数,表示出现的次数。

strings.HasPrefix

fmt.Println(strings.HasPrefix(a, "he")) // true
  • 功能: 判断字符串 a 是否以子字符串 "he" 开头。
  • 返回值: 返回布尔值,表示是否以指定前缀开头。

strings.HasSuffix

fmt.Println(strings.HasSuffix(a, "llo")) // true
  • 功能: 判断字符串 a 是否以子字符串 "llo" 结尾。
  • 返回值: 返回布尔值,表示是否以指定后缀结尾。

strings.Index

fmt.Println(strings.Index(a, "ll")) // 2
  • 功能: 查找子字符串 "ll" 在字符串 a 中的位置。
  • 返回值: 返回整数,表示子字符串的起始位置,如果未找到则返回 -1。

strings.Join

fmt.Println(strings.Join([]string{"he""llo"}, "-")) // he-llo
  • 功能: 将字符串切片 []string{"he", "llo"} 用连接符 "-" 连接成一个字符串。
  • 返回值: 返回连接后的字符串。

strings.Repeat

fmt.Println(strings.Repeat(a, 2)) // hellohello
  • 功能: 将字符串 a 重复 2 次。
  • 返回值: 返回重复后的字符串。

strings.Replace

fmt.Println(strings.Replace(a, "e""E"-1)) // hEllo
  • 功能: 将字符串 a 中的所有 "e" 替换为 "E"
  • 参数: 最后一个参数 -1 表示替换所有匹配项。
  • 返回值: 返回替换后的字符串。

strings.Split

fmt.Println(strings.Split("a-b-c""-")) // [a b c]
  • 功能: 将字符串 "a-b-c" 按照 "-" 分割成字符串切片。
  • 返回值: 返回分割后的字符串切片。

strings.ToLower

fmt.Println(strings.ToLower(a)) // hello
  • 功能: 将字符串 a 转换为小写。
  • 返回值: 返回转换后的字符串。

strings.ToUpper

fmt.Println(strings.ToUpper(a)) // HELLO
  • 功能: 将字符串 a 转换为大写。
  • 返回值: 返回转换后的字符串。

len

fmt.Println(len(a)) // 5

b := "你好"

fmt.Println(len(b)) // 6
  • 功能: 获取字符串的长度。
  • 返回值: 返回字符串的字节长度。注意,对于包含非 ASCII 字符的字符串,长度是以字节为单位的。

总结

  • 字符串包含: 使用 strings.Contains 判断字符串是否包含子字符串。
  • 字符串计数: 使用 strings.Count 统计子字符串出现的次数。
  • 字符串前缀/后缀: 使用 strings.HasPrefix 和 strings.HasSuffix 判断字符串是否以指定前缀或后缀开头/结尾。
  • 字符串查找: 使用 strings.Index 查找子字符串的位置。
  • 字符串连接: 使用 strings.Join 连接字符串切片。
  • 字符串重复: 使用 strings.Repeat 重复字符串。
  • 字符串替换: 使用 strings.Replace 替换字符串中的子字符串。
  • 字符串分割: 使用 strings.Split 分割字符串。
  • 字符串大小写转换: 使用 strings.ToLower 和 strings.ToUpper 进行大小写转换。
  • 字符串长度: 使用 len 获取字符串的字节长度。

字符串格式化

在 Golang 中,字符串格式化是通过标准库 fmt 包提供的各种方法来实现的。fmt.Printf 函数类似于 C 语言中的 printf 函数,但在 Golang 中,格式化字符串更加灵活和强大。

package main
import "fmt"

type point struct {
    x, y int
}

func main() {
    s := "hello"
    n := 123
    p := point{12}
    fmt.Println(s, n) // hello 123
    fmt.Println(p)    // {1 2}
    fmt.Printf("s=%v\n", s)  // s=hello
    fmt.Printf("n=%v\n", n)  // n=123
    fmt.Printf("p=%v\n", p)  // p={1 2}
    fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
    fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
    f := 3.141592653
    fmt.Println(f)          // 3.141592653
    fmt.Printf("%.2f\n", f) // 3.14
}

fmt.Println

fmt.Println(s, n) // hello 123

fmt.Println(p)    // {1 2}
  • 功能fmt.Println 用于打印变量的值,并在末尾添加一个换行符。
  • 自动类型识别fmt.Println 可以自动识别变量的类型并进行打印。

fmt.Printf

fmt.Printf 是一个强大的格式化打印函数,可以根据指定的格式化字符串打印变量的值。

%v 通用占位符
fmt.Printf("s=%v\n", s)  // s=hello

fmt.Printf("n=%v\n", n)  // n=123

fmt.Printf("p=%v\n", p)  // p={1 2}
  • 功能%v 是通用占位符,可以打印任意类型的变量。
  • 自动类型识别: 不需要区分数字、字符串等类型,%v 会自动识别并打印。
%+v 打印详细结果
fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
  • 功能%+v 可以打印结构体的详细字段信息。
  • 详细输出: 输出结构体时,会包含字段名和字段值。
%#v 打印更详细结果
fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
  • 功能%#v 可以打印结构体的完整定义,包括包名、类型名和字段信息。
  • 更详细输出: 输出结构体时,会包含包名、类型名、字段名和字段值。
浮点数格式化
f := 3.141592653

fmt.Println(f)          // 3.141592653

fmt.Printf("%.2f\n", f) // 3.14
  • 功能%.2f 用于格式化浮点数,保留两位小数。
  • 精度控制: 可以通过指定小数点后的位数来控制输出精度。

总结

  • fmt.Println: 用于打印变量的值,并在末尾添加一个换行符。
  • fmt.Printf: 强大的格式化打印函数,可以根据指定的格式化字符串打印变量的值。
    • %v: 通用占位符,可以打印任意类型的变量。
    • %+v: 打印结构体的详细字段信息。
    • %#v: 打印结构体的完整定义,包括包名、类型名和字段信息。
    • %.2f: 格式化浮点数,保留两位小数。

JSON处理

在 Golang 中,JSON 操作非常简单。对于一个已有的结构体,只要保证每个字段的第一个字母是大写(即公开字段),就可以使用json.Marshal将其序列化为 JSON 字符串,使用 json.Unmarshal 将 JSON 字符串反序列化为结构体。

package main

import (
    "encoding/json"
    "fmt"
)

type userInfo struct {
    Name  string   `json:"name"`
    Age   int      `json:"age"`
    Hobby []string `json:"hobby"`
}

func main() {
    a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
    buf, err := json.Marshal(a)
    if err != nil {
        panic(err)
    }
    fmt.Println(buf)         // [123 34 78 97...]
    fmt.Println(string(buf)) // {"name":"wang","age":18,"hobby":["Golang","TypeScript"]}

    buf, err = json.MarshalIndent(a, "", "\t")
    if err != nil {
        panic(err)
    }
    fmt.Println(string(buf))

    var b userInfo
    err = json.Unmarshal(buf, &b)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}

结构体定义与 JSON 标签

type userInfo struct {
    Name  string   `json:"name"`
    Age   int      `json:"age"`
    Hobby []string `json:"hobby"`
}
  • 公开字段: 结构体字段的第一个字母必须大写,表示字段是公开的,这样才能被 JSON 序列化和反序列化。
  • JSON 标签: 使用 json 标签可以指定字段在 JSON 中的名称。例如,Name 字段在 JSON 中的名称为 name

JSON 序列化

buf, err := json.Marshal(a)
if err != nil {
    panic(err)
}
fmt.Println(buf)         // [123 34 78 97...]
fmt.Println(string(buf)) // {"name":"wang","age":18,"hobby":["Golang","TypeScript"]}
  • json.Marshal: 将结构体 a 序列化为 JSON 字符串。
  • 错误处理: 检查 json.Marshal 是否返回错误,如果有错误则使用 panic 终止程序。
  • 输出 JSON: 打印序列化后的 JSON 字符串。

美化 JSON 输出

buf, err = json.MarshalIndent(a, """\t")
if err != nil {
    panic(err)
}
fmt.Println(string(buf))
  • json.MarshalIndent: 将结构体 a 序列化为格式化的 JSON 字符串,便于阅读。
  • 参数: 第二个参数是前缀,第三个参数是缩进字符串,这里使用制表符 \t 进行缩进。

JSON 反序列化

var b userInfo
err = json.Unmarshal(buf, &b)
if err != nil {
    panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
  • json.Unmarshal: 将 JSON 字符串 buf 反序列化为结构体 b
  • 错误处理: 检查 json.Unmarshal 是否返回错误,如果有错误则使用 panic 终止程序。
  • 输出结构体: 使用 fmt.Printf 打印反序列化后的结构体,%#v 格式化输出结构体的详细信息。

总结

  • 公开字段: 结构体字段的第一个字母必须大写,表示字段是公开的,这样才能被 JSON 序列化和反序列化。
  • JSON 标签: 使用 json 标签可以指定字段在 JSON 中的名称。
  • JSON 序列化: 使用 json.Marshal 将结构体序列化为 JSON 字符串。
  • 美化 JSON 输出: 使用 json.MarshalIndent 将结构体序列化为格式化的 JSON 字符串。
  • JSON 反序列化: 使用 json.Unmarshal 将 JSON 字符串反序列化为结构体。

时间处理

在 Golang 中,时间处理主要通过 time 包来实现。常用的操作包括获取当前时间、构造特定时间、格式化时间、解析时间字符串、计算时间差和获取时间戳等。

package main

import (
    "fmt"
    "time"
)

func main() {
    // 获取当前时间
    now := time.Now()
    fmt.Println(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
}

获取当前时间

now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
  • time.Now: 获取当前时间,返回一个 time.Time 类型的值。
  • 输出: 打印当前时间,包括日期、时间和时区信息。

构造特定时间

t := time.Date(2022327125360, time.UTC)
t2 := time.Date(2022327230360, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
  • time.Date: 构造一个特定时间,参数包括年、月、日、时、分、秒、纳秒和时区。
  • 输出: 打印构造的时间。

获取时间的各个部分

fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
  • 方法: 使用 YearMonthDayHour 和 Minute 方法获取时间的各个部分。
  • 输出: 打印时间的年、月、日、小时和分钟。

格式化时间

fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
  • time.Format: 格式化时间为指定格式的字符串。
  • 格式字符串: 使用 2006-01-02 15:04:05 作为格式模板,表示年、月、日、时、分、秒。

计算时间差

diff := t2.Sub(t)
fmt.Println(diff)                           // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
  • time.Sub: 计算两个时间之间的差值,返回一个 time.Duration 类型的值。
  • 方法: 使用 Minutes 和 Seconds 方法获取时间差的分钟数和秒数。
  • 输出: 打印时间差和时间差的分钟数、秒数。

解析时间字符串

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
  • time.Parse: 解析时间字符串为 time.Time 类型的值。
  • 错误处理: 检查 time.Parse 是否返回错误,如果有错误则使用 panic 终止程序。
  • 输出: 比较解析后的时间与原始时间是否相等。

获取时间戳

fmt.Println(now.Unix()) // 1648738080
  • time.Unix: 获取时间的 Unix 时间戳,表示从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间的秒数。
  • 输出: 打印时间戳。

总结

  • 获取当前时间: 使用 time.Now 获取当前时间。
  • 构造特定时间: 使用 time.Date 构造特定时间。
  • 获取时间的各个部分: 使用 YearMonthDayHour 和 Minute 方法获取时间的各个部分。
  • 格式化时间: 使用 time.Format 格式化时间为指定格式的字符串。
  • 计算时间差: 使用 time.Sub 计算两个时间之间的差值。
  • 解析时间字符串: 使用 time.Parse 解析时间字符串为 time.Time 类型的值。
  • 获取时间戳: 使用 time.Unix 获取时间的 Unix 时间戳。

数字解析

在 Golang 中,字符串和数字类型之间的转换主要通过 strconv 包来实现。strconv 是 string convert 的缩写。常用的函数包括 ParseInt、ParseFloat、Atoi 和 Itoa 等

package main

import (
    "fmt"
    "strconv"
)

func main() {
    // 解析浮点数
    f, err := strconv.ParseFloat("1.234", 64)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(f) // 1.234
    }

    // 解析整数
    n, err := strconv.ParseInt("111", 10, 64)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(n) // 111
    }

    // 解析十六进制整数
    n, err = strconv.ParseInt("0x1000", 0, 64)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(n) // 4096
    }

    // Atoi 解析十进制字符串
    n2, err := strconv.Atoi("123")
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println(n2) // 123
    }

    // 解析非法输入
    n2, err = strconv.Atoi("AAA")
    if err != nil {
        fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
    }
}

 strconv.ParseFloat

f, err := strconv.ParseFloat("1.234"64)
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println(f) // 1.234
}
  • 功能: 将字符串解析为浮点数。
  • 参数: 第一个参数是要解析的字符串,第二个参数是浮点数的位数(32 或 64)。
  • 返回值: 返回解析后的浮点数和错误信息。

strconv.ParseInt

n, err := strconv.ParseInt("111"1064)
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println(n) // 111
}
  • 功能: 将字符串解析为整数。
  • 参数: 第一个参数是要解析的字符串,第二个参数是进制(如 10 表示十进制),第三个参数是整数的位数(如 64 表示 64 位整数)。
  • 返回值: 返回解析后的整数和错误信息。

strconv.ParseInt

n, err = strconv.ParseInt("0x1000"064)
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println(n) // 4096
}
  • 功能: 将十六进制字符串解析为整数。
  • 参数: 第二个参数为 0,表示自动检测进制。
  • 返回值: 返回解析后的整数和错误信息。

strconv.Atoi

n2, err := strconv.Atoi("123")
if err != nil {
    fmt.Println("Error:", err)
} else {
    fmt.Println(n2) // 123
}
  • 功能: 将十进制字符串解析为整数。
  • 参数: 要解析的十进制字符串。
  • 返回值: 返回解析后的整数和错误信息。

解析非法输入

n2, err = strconv.Atoi("AAA")
if err != nil {
    fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
}
  • 功能: 解析非法输入时,返回错误信息。
  • 返回值: 返回 0 和错误信息。

总结

  • strconv.ParseFloat: 将字符串解析为浮点数,参数包括字符串和浮点数位数。
  • strconv.ParseInt: 将字符串解析为整数,参数包括字符串、进制和整数位数。
  • strconv.Atoi: 将十进制字符串解析为整数。
  • 错误处理: 如果输入不合法,这些函数都会返回错误信息。

进程信息

在 Golang 中,可以通过 os 包和 os/exec 包来获取和操作进程信息。常用的操作包括获取命令行参数、读取环境变量、设置环境变量和执行外部命令等。

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    // 获取命令行参数
    fmt.Println(os.Args) // [/path/to/executable a b c d]

    // 读取环境变量
    fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...

    // 设置环境变量
    err := os.Setenv("AA", "BB")
    if err != nil {
        panic(err)
    }

    // 执行外部命令
    buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(buf)) // 127.0.0.1       localhost
}

获取命令行参数

fmt.Println(os.Args) // [/path/to/executable a b c d]
  • os.Args: 获取程序执行时指定的命令行参数。
  • 输出os.Args 是一个字符串切片,第一个元素是二进制文件的名称,后面的元素是命令行参数。

例如,运行命令 go run example/20-env/main.go a b c d,输出的 os.Args 会是 [/path/to/executable a b c d]

读取环境变量

fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
  • os.Getenv: 读取指定名称的环境变量。
  • 输出: 返回环境变量的值,如果环境变量不存在,则返回空字符串。

设置环境变量

err := os.Setenv("AA""BB")
if err != nil {
    panic(err)
}
  • os.Setenv: 设置指定名称的环境变量。
  • 参数: 第一个参数是环境变量的名称,第二个参数是环境变量的值。
  • 错误处理: 检查 os.Setenv 是否返回错误,如果有错误则使用 panic 终止程序。

执行外部命令

buf, err := exec.Command("grep""127.0.0.1""/etc/hosts").CombinedOutput()
if err != nil {
    panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1       localhost
  • exec.Command: 创建一个表示外部命令的对象。
  • 参数: 第一个参数是命令名称,后面的参数是命令参数。
  • CombinedOutput: 执行命令并返回标准输出和标准错误的合并结果。
  • 错误处理: 检查 CombinedOutput 是否返回错误,如果有错误则使用 panic 终止程序。
  • 输出: 打印命令的输出结果。

总结

  • 获取命令行参数: 使用 os.Args 获取程序执行时指定的命令行参数。
  • 读取环境变量: 使用 os.Getenv 读取指定名称的环境变量。
  • 设置环境变量: 使用 os.Setenv 设置指定名称的环境变量。
  • 执行外部命令: 使用 exec.Command 创建外部命令对象,并使用 CombinedOutput 执行命令并获取输出结果。