标准库
字符串操作
在 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{1, 2}
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(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
time.Date: 构造一个特定时间,参数包括年、月、日、时、分、秒、纳秒和时区。- 输出: 打印构造的时间。
获取时间的各个部分
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
- 方法: 使用
Year、Month、Day、Hour和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构造特定时间。 - 获取时间的各个部分: 使用
Year、Month、Day、Hour和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", 10, 64)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(n) // 111
}
- 功能: 将字符串解析为整数。
- 参数: 第一个参数是要解析的字符串,第二个参数是进制(如 10 表示十进制),第三个参数是整数的位数(如 64 表示 64 位整数)。
- 返回值: 返回解析后的整数和错误信息。
strconv.ParseInt
n, err = strconv.ParseInt("0x1000", 0, 64)
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执行命令并获取输出结果。