常用标准库
Go 语言标准库功能丰富,覆盖了网络、文件、加密、文本处理等常用场景。
📝
fmt
格式化 I/O
🌐
net/http
HTTP 服务与客户端
🔄
encoding/json
JSON 序列化
📅
time
时间处理
🔍
regexp
正则表达式
🔒
crypto
加密功能
regexp 正则表达式
基础匹配
package main
import (
"fmt"
"regexp"
)
func main() {
// 编译正则表达式
re := regexp.MustCompile(`Hello`)
// 匹配字符串
text := "Hello, World!"
matched := re.MatchString(text)
fmt.Println("Matched:", matched)
// 查找匹配
loc := re.FindStringIndex(text)
fmt.Println("Location:", loc)
}
捕获组
package main
import (
"fmt"
"regexp"
)
func main() {
// 使用捕获组
re := regexp.MustCompile(`(\w+)\s+(\w+)`)
text := "Hello World"
matches := re.FindStringSubmatch(text)
fmt.Println("Full match:", matches[0])
fmt.Println("Group 1:", matches[1])
fmt.Println("Group 2:", matches[2])
}
替换
package main
import (
"fmt"
"regexp"
)
func main() {
// 简单替换
re := regexp.MustCompile(`Hello`)
result := re.ReplaceAllString("Hello World", "Hi")
fmt.Println(result)
// 使用捕获组替换
re2 := regexp.MustCompile(`(\w+)\s+(\w+)`)
result2 := re2.ReplaceAllString("Hello World", "$2 $1")
fmt.Println(result2)
// 使用函数替换
result3 := re2.ReplaceAllStringFunc("Hello World", func(s string) string {
return "REPLACED"
})
fmt.Println(result3)
}
查找所有匹配
package main
import (
"fmt"
"regexp"
)
func main() {
// 查找所有匹配
re := regexp.MustCompile(`\d+`)
text := "I have 2 apples and 3 oranges"
matches := re.FindAllString(text, -1)
fmt.Println("All matches:", matches)
// 查找所有匹配及其位置
matchesWithPos := re.FindAllStringIndex(text, -1)
fmt.Println("Matches with positions:", matchesWithPos)
// 查找所有子匹配
re2 := regexp.MustCompile(`(\w+)\s+(\w+)`)
submatches := re2.FindAllStringSubmatch(text, -1)
fmt.Println("Submatches:", submatches)
}
常用正则表达式
package main
import (
"fmt"
"regexp"
)
func main() {
// 验证邮箱
emailRe := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
fmt.Println("Valid email:", emailRe.MatchString("user@example.com"))
// 验证 URL
urlRe := regexp.MustCompile(`^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`)
fmt.Println("Valid URL:", urlRe.MatchString("https://example.com"))
// 验证手机号(中国)
phoneRe := regexp.MustCompile(`^1[3-9]\d{9}$`)
fmt.Println("Valid phone:", phoneRe.MatchString("13800138000"))
// 提取 HTML 标签内容
htmlRe := regexp.MustCompile(`<[^>]+>([^<]+)[^>]+>`)
html := "Hello
World"
tags := htmlRe.FindAllStringSubmatch(html, -1)
for _, tag := range tags {
fmt.Println("Tag content:", tag[1])
}
}
sync 并发原语
Mutex 互斥锁
package main
import (
"fmt"
"sync"
)
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
func main() {
var counter Counter
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Println("Final value:", counter.Value())
}
RWMutex 读写锁
package main
import (
"fmt"
"sync"
"time"
)
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func NewCache() *Cache {
return &Cache{
data: make(map[string]string),
}
}
func (c *Cache) Get(key string) (string, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
val, ok := c.data[key]
return val, ok
}
func (c *Cache) Set(key, value string) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
func main() {
cache := NewCache()
var wg sync.WaitGroup
// 写入
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
value := fmt.Sprintf("value%d", i)
cache.Set(key, value)
}(i)
}
// 读取
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
time.Sleep(time.Millisecond)
val, ok := cache.Get(key)
fmt.Printf("Get %s: %v, %v\n", key, val, ok)
}(i)
}
wg.Wait()
}
WaitGroup 等待组
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d started\n", id)
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers finished")
}
Once 单次执行
package main
import (
"fmt"
"sync"
)
var (
once sync.Once
instance *Singleton
)
type Singleton struct {
value string
}
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{value: "initialized"}
fmt.Println("Singleton initialized")
})
return instance
}
func main() {
// 多次调用只会初始化一次
GetInstance()
GetInstance()
GetInstance()
}
Cond 条件变量
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
ready := false
// 等待者
go func() {
mu.Lock()
for !ready {
fmt.Println("Waiting...")
cond.Wait()
}
fmt.Println("Ready!")
mu.Unlock()
}()
time.Sleep(time.Second)
// 通知者
mu.Lock()
ready = true
fmt.Println("Signaling...")
cond.Signal()
mu.Unlock()
time.Sleep(time.Second)
}
Pool 对象池
package main
import (
"bytes"
"fmt"
"sync"
)
var bufferPool = sync.Pool{
New: func() interface{} {
fmt.Println("Creating new buffer")
return &bytes.Buffer{}
},
}
func process() {
// 从池中获取
buf := bufferPool.Get().(*bytes.Buffer)
defer func() {
// 重置并放回池中
buf.Reset()
bufferPool.Put(buf)
}()
buf.WriteString("Hello, World!")
fmt.Println("Buffer:", buf.String())
}
func main() {
for i := 0; i < 5; i++ {
process()
}
}
Map 并发安全映射
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
// 存储
m.Store("key1", "value1")
m.Store("key2", "value2")
// 加载
if val, ok := m.Load("key1"); ok {
fmt.Println("key1:", val)
}
// 加载或存储
actual, loaded := m.LoadOrStore("key3", "value3")
fmt.Printf("key3: %v, loaded: %v\n", actual, loaded)
// 遍历
m.Range(func(key, value interface{}) bool {
fmt.Printf("%s: %s\n", key, value)
return true
})
// 删除
m.Delete("key1")
}
Atomic 原子操作
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var counter int64
// 原子增加
atomic.AddInt64(&counter, 1)
fmt.Println("Counter:", counter)
// 原子加载
value := atomic.LoadInt64(&counter)
fmt.Println("Loaded:", value)
// 原子存储
atomic.StoreInt64(&counter, 100)
fmt.Println("Stored:", atomic.LoadInt64(&counter))
// 原子比较并交换
swapped := atomic.CompareAndSwapInt64(&counter, 100, 200)
fmt.Printf("Swapped: %v, Value: %d\n", swapped, atomic.LoadInt64(&counter))
}
json 数据编码
基本编码和解码
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
}
func main() {
// 编码
person := Person{
Name: "Alice",
Age: 30,
}
jsonData, err := json.Marshal(person)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("JSON:", string(jsonData))
// 解码
var decoded Person
err = json.Unmarshal(jsonData, &decoded)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Decoded: %+v\n", decoded)
}
处理嵌套结构
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
Tags []string `json:"tags"`
}
func main() {
jsonData := []byte(`{
"name": "Bob",
"age": 25,
"address": {
"city": "Beijing",
"country": "China"
},
"tags": ["developer", "golang"]
}`)
var user User
err := json.Unmarshal(jsonData, &user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("User: %+v\n", user)
fmt.Printf("Address: %+v\n", user.Address)
fmt.Printf("Tags: %v\n", user.Tags)
}
使用 map 和 interface
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 解码到 map
jsonData := []byte(`{"name": "Charlie", "age": 35}`)
var data map[string]interface{}, ok := m.data[key]
return val, ok
}
func (c *Cache) Set(key, value string) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
func main() {
cache := NewCache()
var wg sync.WaitGroup
// 写入
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
value := fmt.Sprintf("value%d", i)
cache.Set(key, value)
}(i)
}
// 读取
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
key := fmt.Sprintf("key%d", i)
time.Sleep(time.Millisecond)
val, ok := cache.Get(key)
fmt.Printf("Get %s: %v, %v\n", key, val, ok)
}(i)
}
wg.Wait()
}
WaitGroup 等待组
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d started\n", id)
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
fmt.Println("All workers finished")
}
Once 单次执行
package main
import (
"fmt"
"sync"
)
var (
once sync.Once
instance *Singleton
)
type Singleton struct {
value string
}
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{value: "initialized"}
fmt.Println("Singleton initialized")
})
return instance
}
func main() {
// 多次调用只会初始化一次
GetInstance()
GetInstance()
GetInstance()
}
Cond 条件变量
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mu sync.Mutex
cond := sync.NewCond(&mu)
ready := false
// 等待者
go func() {
mu.Lock()
for !ready {
fmt.Println("Waiting...")
cond.Wait()
}
fmt.Println("Ready!")
mu.Unlock()
}()
time.Sleep(time.Second)
// 通知者
mu.Lock()
ready = true
fmt.Println("Signaling...")
cond.Signal()
mu.Unlock()
time.Sleep(time.Second)
}
Pool 对象池
package main
import (
"bytes"
"fmt"
"sync"
)
var bufferPool = sync.Pool{
New: func() interface{} {
fmt.Println("Creating new buffer")
return &bytes.Buffer{}
},
}
func process() {
// 从池中获取
buf := bufferPool.Get().(*bytes.Buffer)
defer func() {
// 重置并放回池中
buf.Reset()
bufferPool.Put(buf)
}()
buf.WriteString("Hello, World!")
fmt.Println("Buffer:", buf.String())
}
func main() {
for i := 0; i < 5; i++ {
process()
}
}
Map 并发安全映射
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
// 存储
m.Store("key1", "value1")
m.Store("key2", "value2")
// 加载
if val, ok := m.Load("key1"); ok {
fmt.Println("key1:", val)
}
// 加载或存储
actual, loaded := m.LoadOrStore("key3", "value3")
fmt.Printf("key3: %v, loaded: %v\n", actual, loaded)
// 遍历
m.Range(func(key, value interface{}) bool {
fmt.Printf("%s: %s\n", key, value)
return true
})
// 删除
m.Delete("key1")
}
Atomic 原子操作
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var counter int64
// 原子增加
atomic.AddInt64(&counter, 1)
fmt.Println("Counter:", counter)
// 原子加载
value := atomic.LoadInt64(&counter)
fmt.Println("Loaded:", value)
// 原子存储
atomic.StoreInt64(&counter, 100)
fmt.Println("Stored:", atomic.LoadInt64(&counter))
// 原子比较并交换
swapped := atomic.CompareAndSwapInt64(&counter, 100, 200)
fmt.Printf("Swapped: %v, Value: %d\n", swapped, atomic.LoadInt64(&counter))
}
json 数据编码
基本编码和解码
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
}
func main() {
// 编码
person := Person{
Name: "Alice",
Age: 30,
}
jsonData, err := json.Marshal(person)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("JSON:", string(jsonData))
// 解码
var decoded Person
err = json.Unmarshal(jsonData, &decoded)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Decoded: %+v\n", decoded)
}
处理嵌套结构
package main
import (
"encoding/json"
"fmt"
)
type Address struct {
City string `json:"city"`
Country string `json:"country"`
}
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
Tags []string `json:"tags"`
}
func main() {
jsonData := []byte(`{
"name": "Bob",
"age": 25,
"address": {
"city": "Beijing",
"country": "China"
},
"tags": ["developer", "golang"]
}`)
var user User
err := json.Unmarshal(jsonData, &user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("User: %+v\n", user)
fmt.Printf("Address: %+v\n", user.Address)
fmt.Printf("Tags: %v\n", user.Tags)
}
使用 map 和 interface
package main
import (
"encoding/json"
"fmt"
)
func main() {
// 解码到 map
jsonData := []byte(`{"name": "Charlie", "age": 35}`)
var data map[string]interface{
err := json.Unmarshal(jsonData, &data)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Name: %v\n", data["name"])
fmt.Printf("Age: %v\n", data["age"])
// 编码 map
newMap := map[string]interface{
"key1": "value1",
"key2": 123,
"key3": true,
}
result, err := json.Marshal(newMap)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Map JSON:", string(result))
}
JSON 流式处理
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
// JSON 数组流
jsonStream := `[{"id":1,"name":"Item1"},{"id":2,"name":"Item2"}]`
decoder := json.NewDecoder(strings.NewReader(jsonStream))
// 读取开始数组标记
t, err := decoder.Token()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Start token:", t)
// 读取数组元素
for decoder.More() {
var item Item
err := decoder.Decode(&item)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Item: %+v\n", item)
}
// 读取结束数组标记
t, err = decoder.Token()
fmt.Println("End token:", t)
}
自定义 JSON 编码
package main
import (
"encoding/json"
"fmt"
"time"
)
type CustomTime struct {
time.Time
}
const customTimeFormat = "2006-01-02 15:04:05"
func (ct *CustomTime) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
t, err := time.Parse(customTimeFormat, s)
if err != nil {
return err
}
ct.Time = t
return nil
}
func (ct CustomTime) MarshalJSON() ([]byte, error) {
return json.Marshal(ct.Format(customTimeFormat))
}
type Event struct {
Name string `json:"name"`
Time CustomTime `json:"time"`
}
func main() {
event := Event{
Name: "Meeting",
Time: CustomTime{time.Now()},
}
jsonData, _ := json.Marshal(event)
fmt.Println("Custom JSON:", string(jsonData))
var decoded Event
json.Unmarshal(jsonData, &decoded)
fmt.Printf("Decoded: %+v\n", decoded)
}
错误处理
package main
import (
"encoding/json"
"fmt"
"errors"
)
type User struct {
Name string `json:"name"`
Age int json:"age,required"
}
func main() {
// 无效 JSON
jsonData := []byte(`{"name": "Test"}`)
var user User
err := json.Unmarshal(jsonData, &user)
if err != nil {
fmt.Println("Unmarshal error:", err)
var syntaxErr *json.SyntaxError
if errors.As(err, &syntaxErr) {
fmt.Printf("Syntax error at offset %d\n", syntaxErr.Offset)
}
var unmarshalErr *json.UnmarshalTypeError
if errors.As(err, &unmarshalErr) {
fmt.Printf("Type error: expected %s, got %s\n",
unmarshalErr.Type, unmarshalErr.Value)
}
}
}
time 时间处理
获取当前时间
package main
import (
"fmt"
"time"
)
func main() {
// 获取当前时间
now := time.Now()
fmt.Println("Current time:", now)
// 获取 UTC 时间
utc := time.Now().UTC()
fmt.Println("UTC time:", utc)
}
时间格式化
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
// 使用预定义格式
fmt.Println("RFC3339:", now.Format(time.RFC3339))
fmt.Println("RFC1123:", now.Format(time.RFC1123))
// 自定义格式(参考 2006-01-02 15:04:05)
fmt.Println("Custom:", now.Format("2006-01-02 15:04:05"))
fmt.Println("Date only:", now.Format("2006-01-02"))
fmt.Println("Time only:", now.Format("15:04:05"))
}
时间解析
package main
import (
"fmt"
"time"
)
func main() {
// 解析时间字符串
timeStr := "2024-01-26 15:30:45"
parsedTime, err := time.Parse("2006-01-02 15:04:05", timeStr)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Parsed time:", parsedTime)
// 解析 RFC3339 格式
rfcTime, err := time.Parse(time.RFC3339, "2024-01-26T15:30:45Z")
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("RFC3339 time:", rfcTime)
}
时间计算
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
// 添加时间
future := now.Add(24 * time.Hour)
fmt.Println("24 hours later:", future)
// 减去时间
past := now.Add(-24 * time.Hour)
fmt.Println("24 hours ago:", past)
// 计算时间差
duration := future.Sub(now)
fmt.Println("Duration:", duration)
fmt.Println("Hours:", duration.Hours())
fmt.Println("Minutes:", duration.Minutes())
// 计算两个时间之间的天数
days := duration.Hours() / 24
fmt.Println("Days:", days)
}
定时器和 Ticker
package main
import (
"fmt"
"time"
)
func main() {
// Timer:一次性定时器
timer := time.NewTimer(2 * time.Second)
<-timer.C
fmt.Println("Timer expired")
// Ticker:周期性定时器
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for i := 0; i < 3; i++ {
<-ticker.C
fmt.Printf("Tick %d\n", i)
}
}
时区处理
package main
import (
"fmt"
"time"
)
func main() {
// 加载时区
loc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
fmt.Println("Error:", err)
return
}
// 在指定时区创建时间
now := time.Now().In(loc)
fmt.Println("Shanghai time:", now)
// 转换时区
nyLoc, _ := time.LoadLocation("America/New_York")
nyTime := now.In(nyLoc)
fmt.Println("New York time:", nyTime)
}
io 输入输出
读取文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
file, err := os.Open("test.txt")
if err != nil {
fmt.Println("Error:", err)
return
}
defer file.Close()
// 读取整个文件
data, err := io.ReadAll(file)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("File content:", string(data))
}
写入文件
package main
import (
"fmt"
"os"
)
func main() {
// 写入文件(覆盖)
err := os.WriteFile("output.txt", []byte("Hello, World!"), 0644)
if err != nil {
fmt.Println("Error:", err)
return
}
// 追加写入
f, err := os.OpenFile("output.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Error:", err)
return
}
defer f.Close()
_, err = f.WriteString("\nAppended text")
if err != nil {
fmt.Println("Error:", err)
}
}
读取目录
package main
import (
"fmt"
"os"
)
func main() {
// 读取目录内容
entries, err := os.ReadDir(".")
if err != nil {
fmt.Println("Error:", err)
return
}
for _, entry := range entries {
fmt.Printf("%s (%v)\n", entry.Name(), entry.IsDir())
}
}
创建和删除文件/目录
package main
import (
"fmt"
"os"
)
func main() {
// 创建目录
err := os.MkdirAll("testdir/subdir", 0755)
if err != nil {
fmt.Println("Error:", err)
}
// 创建文件
file, err := os.Create("testdir/test.txt")
if err != nil {
fmt.Println("Error:", err)
}
file.Close()
// 删除文件
os.Remove("testdir/test.txt")
// 删除目录
os.RemoveAll("testdir")
}
使用 io.Copy
package main
import (
"io"
"os"
)
func copyFile(src, dst string) error {
source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
return err
}
使用 io.LimitReader
package main
import (
"fmt"
"io"
"strings"
)
func main() {
reader := strings.NewReader("Hello, World! This is a long string.")
// 限制读取 5 个字节
limitedReader := io.LimitReader(reader, 5)
data, _ := io.ReadAll(limitedReader)
fmt.Println("Limited read:", string(data))
}
bufio 缓冲 I/O
缓冲读取
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, _ := os.Open("test.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
// 逐行读取
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
缓冲写入
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, _ := os.Create("output.txt")
defer file.Close()
writer := bufio.NewWriter(file)
defer writer.Flush()
for i := 0; i < 10; i++ {
fmt.Fprintln(writer, "Line", i)
}
}
从标准输入读取
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Enter your name: ")
scanner.Scan()
name := scanner.Text()
fmt.Printf("Hello, %s!\n", name)
}
读取分隔符
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
reader := strings.NewReader("apple,banana,cherry")
scanner := bufio.NewScanner(reader)
// 设置分隔符
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}
使用 bufio.Reader
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, _ := os.Open("test.txt")
defer file.Close()
reader := bufio.NewReader(file)
// 读取到分隔符
line, _ := reader.ReadString('\n')
fmt.Println("Line:", line)
// 读取字节
data := make([]byte, 10)
n, _ := reader.Read(data)
fmt.Printf("Read %d bytes: %s\n", n, data)
}
使用 bufio.Writer
package main
import (
"bufio"
"os"
)
func main() {
file, _ := os.Create("output.txt")
defer file.Close()
writer := bufio.NewWriter(file)
// 写入字节
writer.Write([]byte("Hello"))
// 写入字符串
writer.WriteString(", World!")
// 刷新缓冲区
writer.Flush()
}
Embed 简介
embed 是 Go 1.16 引入的标准库,用于在编译时将文件嵌入到 Go 程序中。它提供了一种简单、类型安全的方式来访问嵌入的文件,无需在运行时读取文件系统。
Embed 的核心特性
- 编译时嵌入:文件在编译时被嵌入到二进制文件中
- 类型安全:提供 string、[]byte 和 fs.FS 类型
- 跨平台:自动处理不同操作系统的路径分隔符
- 零依赖:不需要额外的依赖管理
- 简单易用:通过 //go:embed 指令声明
最佳实践
regexp 最佳实践
package main
import (
"regexp"
"sync"
)
// 1. 预编译正则表达式
var (
emailRe = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
phoneRe = regexp.MustCompile(`^1[3-9]\d{9}$`)
reCache = make(map[string]*regexp.Regexp)
reCacheMu sync.RWMutex
)
// 2. 缓存正则表达式
func GetRegex(pattern string) (*regexp.Regexp, error) {
reCacheMu.RLock()
re, ok := reCache[pattern]
reCacheMu.RUnlock()
if ok {
return re, nil
}
re, err := regexp.Compile(pattern)
if err != nil {
return nil, err
}
reCacheMu.Lock()
reCache[pattern] = re
reCacheMu.Unlock()
return re, nil
}
// 3. 使用原始字符串避免转义
// 好:`\d+`
// 坏:"\d+"
// 4. 避免贪婪匹配
// 好:`<.*?>`
// 坏:`<.*>`
// 5. 使用非捕获组
// 好:`(?:a|b)c`
// 坏:`(a|b)c`
sync 最佳实践
package main
import (
"sync"
)
// 1. 避免锁的嵌套
type SafeCounter struct {
mu sync.Mutex
value int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
// 2. 使用 defer 确保锁释放
func (c *SafeCounter) Get() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
// 3. 读写锁用于读多写少场景
type SafeMap struct {
mu sync.RWMutex
data map[string]string
}
func (m *SafeMap) Get(key string) (string, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}
func (m *SafeMap) Set(key, value string) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[key] = value
}
// 4. 使用 sync.Pool 重用对象
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 0, 1024)
},
}
func getBuffer() []byte {
return bufferPool.Get().([]byte)
}
func putBuffer(buf []byte) {
bufferPool.Put(buf[:0])
}
// 5. 使用 sync.Map 替代 map+Mutex(特定场景)
// 适用于:读多写少、键值对稳定
json 最佳实践
package main
import (
"encoding/json"
)
// 1. 使用结构体标签
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Password string json:"-"` // 忽略
Email string `json:"email,omitempty"` // 空值忽略
}
// 2. 使用指针处理可选字段
type Config struct {
Timeout *int `json:"timeout,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
}
// 3. 使用 json.RawMessage 延迟解析
type Message struct {
Type string `json:"type"`
Payload json.RawMessage `json:"payload"`
}
// 4. 使用 json.Number 处理大数字
type Data struct {
ID json.Number `json:"id"`
}
// 5. 验证 JSON 结构
func validateJSON(data []byte) bool {
var v interface{
return json.Valid(data)
}
// 6. 使用 json.Encoder/Decoder 处理流
// 适用于大文件或网络流
// 7. 处理自定义时间格式
type CustomTime struct {
time.Time
}
func (ct *CustomTime) UnmarshalJSON(b []byte) error {
s := string(b)
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
ct.Time = t
return nil
}
exp 实验性标准库
简介
exp(experimental)是 Go 语言的实验性标准库,包含了一些新功能和实验性的实现。这些库可能会在未来成为标准库的一部分,也可能被移除或修改。常用的 exp 库包括 expvar(变量监控)、slog(结构化日志)等。
expvar 变量监控
expvar 提供了一种标准化的方式来发布和监控运行时的变量,特别适合用于监控和调试。
基本使用
package main
import (
"expvar"
"fmt"
"net/http"
"time"
)
var (
requests = expvar.NewInt("requests")
errors = expvar.NewInt("errors")
connections = expvar.NewInt("connections")
)
func main() {
// 注册 HTTP 处理器
http.Handle("/debug/vars", expvar.Handler())
// 模拟请求处理
go func() {
for {
requests.Add(1)
time.Sleep(time.Second)
}
}()
fmt.Println("Server started on :8080")
fmt.Println("Visit http://localhost:8080/debug/vars to see metrics")
http.ListenAndServe(":8080", nil)
}
自定义变量
package main
import (
"expvar"
"fmt"
"sync"
)
// 自定义计数器
type Counter struct {
mu sync.Mutex
count int
}
func (c *Counter) String() string {
c.mu.Lock()
defer c.mu.Unlock()
return fmt.Sprintf("%d", c.count)
}
func (c *Counter) Add(n int) {
c.mu.Lock()
defer c.mu.Unlock()
c.count += n
}
var customCounter = &Counter{}
func init() {
expvar.Publish("custom_counter", customCounter)
}
func main() {
customCounter.Add(1)
customCounter.Add(2)
// 获取变量值
val := expvar.Get("custom_counter")
fmt.Println("Custom counter:", val.String())
}
Map 类型
package main
import (
"expvar"
"fmt"
)
var (
// 创建 Map
stats = expvar.NewMap("stats")
)
func main() {
// 添加键值对
stats.Add("requests", 100)
stats.Add("errors", 5)
// 设置值
stats.Set("version", expvar.String("1.0.0"))
// 获取值
requests := stats.Get("requests")
fmt.Println("Requests:", requests.String())
// 遍历所有键
stats.Do(func(kv expvar.KeyValue) bool {
fmt.Printf("%s: %s\n", kv.Key, kv.Value.String())
return true
})
}
Float 类型
var (
cpuUsage = expvar.NewFloat("cpu_usage")
memory = expvar.NewFloat("memory_usage")
)
func updateMetrics() {
cpuUsage.Set(45.5)
memory.Set(1024.5)
}
String 类型
var (
version = expvar.NewString("version")
buildTime = expvar.NewString("build_time")
)
func init() {
version.Set("1.0.0")
buildTime.Set("2024-01-01 00:00:00")
}
在 Web 服务器中使用
package main
import (
"expvar"
"fmt"
"net/http"
"time"
)
var (
requestCount = expvar.NewInt("request_count")
errors = expvar.NewInt("errors")
avgTime = expvar.NewFloat("avg_time_ms")
)
func handler(w http.ResponseWriter, r *http.Request) {
start := time.Now()
requestCount.Add(1)
// 模拟处理
time.Sleep(time.Millisecond * 10)
// 计算平均时间
elapsed := time.Since(start).Milliseconds()
avgTime.Set(float64(elapsed))
fmt.Fprintln(w, "Hello, World!")
}
func main() {
// 注册 expvar 处理器
http.Handle("/debug/vars", expvar.Handler())
// 注册业务处理器
http.HandleFunc("/", handler)
fmt.Println("Server started on :8080")
fmt.Println("Metrics: http://localhost:8080/debug/vars")
http.ListenAndServe(":8080", nil)
}
slog 结构化日志
slog 是 Go 1.21+ 引入的结构化日志库,提供了结构化的日志记录功能,比传统的 log 包更强大和灵活。
基本使用
package main
import (
"log/slog"
"os"
)
func main() {
// 创建默认 logger
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
// 记录不同级别的日志
logger.Debug("Debug message")
logger.Info("Info message")
logger.Warn("Warning message")
logger.Error("Error message")
}
结构化字段
package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// 添加结构化字段
logger.Info("User logged in",
slog.String("user_id", "123"),
slog.String("username", "alice"),
slog.String("ip", "192.168.1.1"),
)
logger.Error("Request failed",
slog.String("path", "/api/users"),
slog.Int("status", 500),
slog.Duration("duration_ms", 150),
)
}
自定义 Handler
package main
import (
"context"
"encoding/json"
"log/slog"
"os"
)
// 自定义 Handler
type CustomHandler struct {
slog.Handler
}
func (h *CustomHandler) Handle(ctx context.Context, r slog.Record) error {
// 添加自定义字段
r.AddAttrs(slog.String("service", "myapp"))
return h.Handler.Handle(ctx, r)
}
func main() {
handler := &CustomHandler{
Handler: slog.NewJSONHandler(os.Stdout, nil),
}
logger := slog.New(handler)
logger.Info("Test message")
}
日志级别控制
package main
import (
"log/slog"
"os"
)
func main() {
// 设置日志级别
opts := &slog.HandlerOptions{
Level: slog.LevelInfo,
}
logger := slog.New(slog.NewJSONHandler(os.Stdout, opts))
// Debug 级别的日志不会输出
logger.Debug("Debug message")
logger.Info("Info message")
}
上下文支持
package main
import (
"context"
"log/slog"
"os"
)
type contextKey struct{}
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// 在上下文中添加值
ctx := context.WithValue(context.Background(), contextKey{}, "request-123")
// 使用上下文记录日志
logger.InfoContext(ctx, "Processing request")
}
分组日志
package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
// 使用分组
logger.Info("User action",
slog.Group("user",
slog.String("id", "123"),
slog.String("name", "alice"),
),
slog.Group("request",
slog.String("path", "/api/users"),
slog.String("method", "GET"),
),
)
}
与 Gin 集成
package main
import (
"log/slog"
"net/http"
"github.com/gin-gonic/gin"
)
var logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
func main() {
r := gin.Default()
// 自定义中间件
r.Use(func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
c.Next()
logger.Info("Request",
slog.String("method", c.Request.Method),
slog.String("path", path),
slog.Int("status", c.Writer().Status()),
slog.Duration("duration", time.Since(start)),
)
})
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello, World!")
})
r.Run(":8080")
}
exp 最佳实践
1. expvar 使用建议
- 监控关键指标:监控请求计数、错误计数、连接数等关键指标
- 原子操作:使用 expvar.Int 和 expvar.Float 确保线程安全
- 合理命名:使用有意义的变量名,便于理解
- 定期清理:避免积累过多的监控数据
- 安全考虑:在生产环境中限制 /debug/vars 的访问权限
2. slog 使用建议
- 结构化字段:使用结构化字段而不是字符串拼接
- 日志级别:合理使用不同级别的日志
- 上下文传递:使用上下文传递请求相关信息
- 性能考虑:避免在高频路径中记录过多日志
- 日志轮转:配合日志轮转工具管理日志文件
3. 集成建议
// 在应用启动时初始化
func InitMonitoring() {
// 注册 expvar
expvar.Publish("version", expvar.String(Version))
expvar.Publish("build_time", expvar.String(BuildTime))
// 初始化 logger
opts := &slog.HandlerOptions{
Level: slog.LevelInfo,
}
logger = slog.New(slog.NewJSONHandler(os.Stdout, opts))
}
性能优化建议
- regexp:预编译正则表达式,避免重复编译
- sync:根据场景选择合适的锁类型,避免锁竞争
- json:使用流式处理大文件,避免内存溢出
- sync.Pool:重用大对象,减少 GC 压力
- atomic:对简单类型使用原子操作,避免锁开销
- expvar:使用原子操作更新指标,避免锁竞争
- slog:在生产环境中使用 JSON 格式,便于日志分析