golang中数据类型转换与定时器的使用

其实你心里早就有了答案,你就是不想承认

Posted by yishuifengxiao on 2024-03-15

基础数据类型转换

在 Go 语言中,数据类型转换需要显式操作,主要分为以下几种情况:

数值类型互转

var i int = 42

// int -> float
f := float64(i) // 42.0

// int -> uint
u := uint(i) // 42

// float -> int (截断小数)
f2 := 3.14
i2 := int(f2) // 3 (小数部分丢失)

字符串与基本类型互转

使用 strconv 包:

import "strconv"

// int -> string
s := strconv.Itoa(65) // "65"
s = strconv.FormatInt(123, 10) // 十进制 "123"

// string -> int
num, err := strconv.Atoi("65") // 65
num2, err := strconv.ParseInt("FF", 16, 64) // 十六进制解析,255

// float -> string
s := strconv.FormatFloat(3.1415, 'f', 2, 64) // "3.14"

// string -> float
f, err := strconv.ParseFloat("3.14", 64) // 3.14

// bool -> string
s := strconv.FormatBool(true) // "true"

// string -> bool
b, err := strconv.ParseBool("true")

字节切片([]byte)与字符串

// string -> []byte
data := []byte("Hello") // [72 101 108 108 111]

data1 := []byte("你好") // [228 189 160 229 165 189]

// []byte -> string
str := string(data) // "Hello"

符文切片([]rune)与字符串

// string -> []rune
runes := []rune("你好") // [20320 22909]
runes1 := []rune("Hello") // [72 101 108 108 111]

// []rune -> string
str := string(runes) // "你好"

接口类型断言

var val interface{} = "hello"

// 安全类型断言
s, ok := val.(string) // s="hello", ok=true
// i, ok := val.(int) // ok=false

// 非安全断言 (失败会panic)
s2 := val.(string) // "hello"

自定义类型转换

type Celsius float64
type Fahrenheit float64

c := Celsius(100)
f := Fahrenheit(c*9/5 + 32) // 需显式转换

// 底层相同类型可互转
var f2 float64 = float64(c) // 100.0

JSON 转换

import "encoding/json"

type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}

// 结构体 -> JSON
p := Person{"Alice", 30}
jsonData, _ := json.Marshal(p)
// {"name":"Alice","age":30}

// JSON -> 结构体
var p2 Person
json.Unmarshal(jsonData, &p2)

重要注意事项

  1. 精度损失:大类型转小类型时可能丢失数据

    var big int64 = 1<<33 + 1
    small := int32(big) // 数据截断
  2. 非法转换:编译器会阻止不兼容转换

    // 编译错误示例:
    // var s string = 65 // 必须用 strconv
    // var b bool = 1 // 不允许
  3. 类型断言要求:接口转换必须实际存储目标类型

  4. 字符串转换性能

    // 高性能转换 (避免拷贝)
    str := "hello"
    unsafeBytes := *(*[]byte)(unsafe.Pointer(&str))

建议:

  • 数值转换注意范围检查
  • 优先使用 strconv 而非 fmt.Sprintf
  • 大切片转换考虑 unsafe(需谨慎)
  • 使用 , ok 格式避免断言 panic

通过显式类型转换和标准库函数,Go 在保持类型安全的同时提供了灵活的类型转换机制。


字符串与日期时间的互相转换

在 Go 语言中,时间处理主要依赖于标准库中的 time 包。下面我将详细解释字符串与时间对象之间的转换方法,并提供一个完整的可视化示例。

核心转换方法

时间对象转字符串

使用 time.Format(layout string) 方法,其中 layout 必须是 Go 的参考时间(2006-01-02 15:04:05)

t := time.Now()
str := t.Format("2006-01-02 15:04:05") // 输出: "2023-07-15 14:30:45"

字符串转时间对象

使用 time.Parse(layout, value string)time.ParseInLocation()

layout := "2006-01-02"
str := "2023-07-15"
t, err := time.Parse(layout, str)

完整示例代码

package main

import (
"fmt"
"time"
)

func main() {
// 当前时间
now := time.Now()

// 1. 时间转字符串
fmt.Println("=== 时间转字符串 ===")
fmt.Println("默认格式:", now.String())
fmt.Println("RFC3339格式:", now.Format(time.RFC3339))
fmt.Println("自定义格式:", now.Format("2006年01月02日 15:04:05"))
fmt.Println("日期部分:", now.Format("2006-01-02"))
fmt.Println("时间部分:", now.Format("15:04:05"))
fmt.Println("Unix时间戳:", now.Unix())

// 2. 字符串转时间
fmt.Println("\n=== 字符串转时间 ===")

// 解析 RFC3339 格式
rfcStr := "2023-07-15T14:30:45+08:00"
t1, _ := time.Parse(time.RFC3339, rfcStr)
fmt.Println("解析 RFC3339:", t1)

// 解析自定义格式
customStr := "2023-07-15 14:30:45"
t2, _ := time.Parse("2006-01-02 15:04:05", customStr)
fmt.Println("解析自定义格式:", t2)

// 解析日期
dateStr := "2023-07-15"
t3, _ := time.Parse("2006-01-02", dateStr)
fmt.Println("解析日期:", t3.Format("2006-01-02"))

// 带时区解析
localStr := "2023-07-15 14:30:45"
loc, _ := time.LoadLocation("Asia/Shanghai")
t4, _ := time.ParseInLocation("2006-01-02 15:04:05", localStr, loc)
fmt.Println("带时区解析:", t4)

// 3. 时间计算
fmt.Println("\n=== 时间计算 ===")
tomorrow := now.Add(24 * time.Hour)
fmt.Println("明天:", tomorrow.Format("2006-01-02"))

duration := tomorrow.Sub(now)
fmt.Println("时间差:", duration.Round(time.Hour))

// 4. 时间戳转换
fmt.Println("\n=== 时间戳转换 ===")
ts := now.Unix()
fmt.Println("当前时间戳:", ts)

tsTime := time.Unix(ts, 0)
fmt.Println("时间戳转时间:", tsTime.Format(time.RFC3339))

// 5. 时区处理
fmt.Println("\n=== 时区处理 ===")
utcTime := now.UTC()
fmt.Println("UTC时间:", utcTime.Format(time.RFC3339))

nyLoc, _ := time.LoadLocation("America/New_York")
nyTime := now.In(nyLoc)
fmt.Println("纽约时间:", nyTime.Format("2006-01-02 15:04:05 MST"))
}

常用时间格式布局

布局字符串 示例输出 说明
time.RFC3339 “2006-01-02T15:04:05Z07:00” ISO8601/RFC3339 格式
time.RFC3339Nano “2006-01-02T15:04:05.999999999Z07:00” 带纳秒的 RFC3339
time.RFC1123 “Mon, 02 Jan 2006 15:04:05 MST” HTTP 头常用格式
“2006-01-02” “2023-07-15” 年-月-日
“15:04:05” “14:30:45” 时:分:秒
“2006/01/02 15:04” “2023/07/15 14:30” 自定义格式
“Jan _2, 2006” “Jul 15, 2023” 月名 日, 年
“20060102” “20230715” 紧凑日期格式

重要注意事项

  1. 布局字符串必须使用参考时间
    Go 使用 2006-01-02 15:04:05 作为布局模板,必须精确使用这些数字

  2. 时区处理

    • time.Parse() 默认使用 UTC 时区
    • 对于本地时间,使用 time.ParseInLocation()
    • 显示指定时区:"2006-01-02 15:04:05 MST"
  3. 错误处理
    总是检查 time.Parse() 返回的错误:

    t, err := time.Parse(layout, value)
    if err != nil {
    // 处理错误
    }
  4. 性能考虑

    • 重复使用 time.Parse() 时,预编译布局可以提高性能
    • 对于高吞吐场景,考虑使用时间戳代替字符串
  5. 时间计算

    • 使用 time.Add() 进行时间加减
    • 使用 time.Sub() 计算时间差
    • 使用 time.Truncate()time.Round() 进行时间取整

时间戳与日期时间的转换、时间计算和比较

在 Go 语言中,处理时间戳和日期时间的转换、时间计算以及时间点比较是常见的任务。下面我将详细解释这些操作,并提供实用的代码示例。

时间戳与日期时间的互相转换

时间戳转日期时间

package main

import (
"fmt"
"time"
)

func main() {
// 获取当前时间戳(秒级和毫秒级)
now := time.Now()
unixSec := now.Unix() // 秒级时间戳
unixMilli := now.UnixMilli() // 毫秒级时间戳 (Go 1.17+)
unixMicro := now.UnixMicro() // 微秒级时间戳 (Go 1.17+)
unixNano := now.UnixNano() // 纳秒级时间戳

fmt.Printf("当前时间: %s\n", now.Format("2006-01-02 15:04:05.999999"))
fmt.Printf("秒级时间戳: %d\n", unixSec)
fmt.Printf("毫秒级时间戳: %d\n", unixMilli)
fmt.Printf("微秒级时间戳: %d\n", unixMicro)
fmt.Printf("纳秒级时间戳: %d\n", unixNano)

// 时间戳转日期时间
// 秒级时间戳转时间
t1 := time.Unix(unixSec, 0)
fmt.Printf("秒级时间戳转时间: %s\n", t1.Format("2006-01-02 15:04:05"))

// 毫秒级时间戳转时间 (Go 1.17+)
t2 := time.UnixMilli(unixMilli)
fmt.Printf("毫秒级时间戳转时间: %s\n", t2.Format("2006-01-02 15:04:05.000"))

// 微秒级时间戳转时间 (Go 1.17+)
t3 := time.UnixMicro(unixMicro)
fmt.Printf("微秒级时间戳转时间: %s\n", t3.Format("2006-01-02 15:04:05.000000"))

// 纳秒级时间戳转时间
t4 := time.Unix(0, unixNano)
fmt.Printf("纳秒级时间戳转时间: %s\n", t4.Format("2006-01-02 15:04:05.99999999"))

// 处理不同时区
loc, _ := time.LoadLocation("America/New_York")
t5 := time.Unix(unixSec, 0).In(loc)
fmt.Printf("纽约时间: %s\n", t5.Format("2006-01-02 15:04:05 MST"))
}

日期时间转时间戳

func datetimeToTimestamp() {
// 字符串转时间对象
layout := "2006-01-02 15:04:05"
str := "2023-07-15 14:30:45"
t, _ := time.Parse(layout, str)

// 获取各种精度的时间戳
sec := t.Unix()
milli := t.UnixMilli() // Go 1.17+
micro := t.UnixMicro() // Go 1.17+
nano := t.UnixNano()

fmt.Printf("\n时间: %s\n", t)
fmt.Printf("秒级时间戳: %d\n", sec)
fmt.Printf("毫秒级时间戳: %d\n", milli)
fmt.Printf("微秒级时间戳: %d\n", micro)
fmt.Printf("纳秒级时间戳: %d\n", nano)

// 处理不同时区的时间戳
loc, _ := time.LoadLocation("Asia/Tokyo")
tokyoTime, _ := time.ParseInLocation(layout, "2023-07-15 14:30:45", loc)
fmt.Printf("东京时间戳: %d (UTC时间: %s)\n", tokyoTime.Unix(), tokyoTime.UTC())
}

时间加减操作

基本时间加减

func timeArithmetic() {
now := time.Now()
fmt.Printf("\n当前时间: %s\n", now.Format("2006-01-02 15:04:05"))

// 加减时间间隔
oneHourLater := now.Add(time.Hour)
fmt.Printf("1小时后: %s\n", oneHourLater.Format("15:04:05"))

twoDaysAgo := now.Add(-48 * time.Hour)
fmt.Printf("2天前: %s\n", twoDaysAgo.Format("2006-01-02"))

// 加减年/月/日
nextMonth := now.AddDate(0, 1, 0)
fmt.Printf("1个月后: %s\n", nextMonth.Format("2006-01-02"))

nextYear := now.AddDate(1, 0, 0)
fmt.Printf("1年后: %s\n", nextYear.Format("2006-01-02"))

tenDaysLater := now.AddDate(0, 0, 10)
fmt.Printf("10天后: %s\n", tenDaysLater.Format("2006-01-02"))

// 复杂时间计算
complexTime := now.Add(2*time.Hour + 30*time.Minute + 15*time.Second)
fmt.Printf("2小时30分15秒后: %s\n", complexTime.Format("15:04:05"))
}

计算时间差

func timeDifference() {
start := time.Date(2023, 7, 1, 9, 0, 0, 0, time.UTC)
end := time.Date(2023, 7, 15, 14, 30, 45, 0, time.UTC)

duration := end.Sub(start)

fmt.Printf("\n时间差计算:\n")
fmt.Printf("开始时间: %s\n", start.Format("2006-01-02 15:04:05"))
fmt.Printf("结束时间: %s\n", end.Format("2006-01-02 15:04:05"))
fmt.Printf("总时间差: %v\n", duration)
fmt.Printf("天数: %.1f\n", duration.Hours()/24)
fmt.Printf("小时: %.1f\n", duration.Hours())
fmt.Printf("分钟: %.1f\n", duration.Minutes())
fmt.Printf("秒数: %.1f\n", duration.Seconds())

// 计算到特定时间点还有多久
deadline := time.Date(2023, 12, 31, 23, 59, 59, 0, time.UTC)
timeLeft := time.Until(deadline)
fmt.Printf("\n距离2023年底还有: %d天 %d小时\n",
int(timeLeft.Hours()/24),
int(timeLeft.Hours())%24)
}

时间点前后判断

基本时间比较

func timeComparison() {
now := time.Now()
past := now.Add(-1 * time.Hour)
future := now.Add(1 * time.Hour)

fmt.Printf("\n时间比较:\n")
fmt.Printf("当前时间: %s\n", now.Format("15:04:05"))
fmt.Printf("过去时间: %s\n", past.Format("15:04:05"))
fmt.Printf("未来时间: %s\n", future.Format("15:04:05"))

// 使用 Before, After, Equal 方法
fmt.Printf("\n过去时间在当前时间之前? %t\n", past.Before(now))
fmt.Printf("未来时间在当前时间之后? %t\n", future.After(now))
fmt.Printf("当前时间等于现在? %t\n", now.Equal(time.Now())) // 可能有微小差异

// 使用比较运算符
fmt.Printf("\n使用比较运算符:\n")
fmt.Printf("past < now? %t\n", past.Before(now))
fmt.Printf("now < future? %t\n", now.Before(future))
fmt.Printf("past < future? %t\n", past.Before(future))
}

时间范围判断

func timeRangeCheck() {
now := time.Now()

// 定义工作时间段 (9:00-18:00)
startWork := time.Date(now.Year(), now.Month(), now.Day(), 9, 0, 0, 0, now.Location())
endWork := time.Date(now.Year(), now.Month(), now.Day(), 18, 0, 0, 0, now.Location())

fmt.Printf("\n工作时间范围判断:\n")
fmt.Printf("当前时间: %s\n", now.Format("15:04:05"))
fmt.Printf("工作时间: %s - %s\n",
startWork.Format("15:04"),
endWork.Format("15:04"))

// 检查是否在工作时间内
if now.After(startWork) && now.Before(endWork) {
fmt.Println("现在是工作时间")
} else {
fmt.Println("现在是非工作时间")
}

// 检查是否在周末
if now.Weekday() == time.Saturday || now.Weekday() == time.Sunday {
fmt.Println("今天是周末")
} else {
fmt.Println("今天是工作日")
}
}

定时器与超时判断

func timerAndTimeout() {
fmt.Println("\n定时器与超时示例:")

// 创建一个2秒的定时器
timeout := 2 * time.Second
start := time.Now()
timer := time.NewTimer(timeout)

fmt.Printf("开始时间: %s\n", start.Format("15:04:05"))

// 等待定时器触发
<-timer.C
fmt.Printf("定时器触发: %s (等待了 %v)\n",
time.Now().Format("15:04:05"),
time.Since(start))

// 超时判断示例
result := make(chan string)
go func() {
// 模拟长时间操作
time.Sleep(3 * time.Second)
result <- "操作完成"
}()

select {
case res := <-result:
fmt.Println(res)
case <-time.After(2 * time.Second):
fmt.Println("操作超时!")
}
}

完整示例代码

package main

import (
"fmt"
"time"
)

func main() {
// 时间戳与日期时间转换
timestampConversion()
datetimeToTimestamp()

// 时间计算
timeArithmetic()
timeDifference()

// 时间比较
timeComparison()
timeRangeCheck()

// 定时器与超时
timerAndTimeout()
}

// 这里插入前面定义的所有函数...

关键点总结

  1. 时间戳转换

    • 使用 time.Unix() 将秒级时间戳转为时间
    • 使用 time.UnixMilli() (Go 1.17+) 将毫秒级时间戳转为时间
    • 使用 time.Unix(0, nanos) 将纳秒级时间戳转为时间
    • 使用 .Unix(), .UnixMilli(), .UnixMicro(), .UnixNano() 获取各种精度的时间戳
  2. 时间加减

    • 使用 .Add(duration) 添加时间间隔
    • 使用 .AddDate(years, months, days) 添加年/月/日
    • 使用 .Sub() 计算两个时间点之间的差值
  3. 时间比较

    • 使用 .Before() 检查一个时间是否在另一个之前
    • 使用 .After() 检查一个时间是否在另一个之后
    • 使用 .Equal() 检查两个时间是否相等
    • 使用 time.Until() 计算到未来时间点的剩余时间
    • 使用 time.Since() 计算从过去时间点到现在的时间
  4. 最佳实践

    • 始终使用时区感知的时间操作
    • 对于高精度需求,使用纳秒级时间戳
    • 在分布式系统中使用 UTC 时间
    • 使用 time.Timertime.Ticker 处理定时任务
    • 使用 context.WithTimeout 处理超时控制

定时器的创建与管理

在 Go 语言中,定时器主要通过 time 包提供的功能来实现。下面我将详细介绍如何创建定时器、设置频率以及启动和停止定时器。

定时器类型与创建方法

一次性定时器 (Timer)

package main

import (
"fmt"
"time"
)

func main() {
// 创建定时器 - 3秒后触发
timer := time.NewTimer(3 * time.Second)

fmt.Println("定时器已创建,等待触发...")

// 等待定时器触发
<-timer.C
fmt.Println("定时器触发!")

// 尝试停止已触发的定时器
if !timer.Stop() {
fmt.Println("定时器已触发,无法停止")
}
}

周期性定时器 (Ticker)

func tickerExample() {
// 创建周期性定时器 - 每秒触发一次
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() // 确保结束时停止

done := make(chan bool)

// 启动协程处理定时任务
go func() {
for i := 1; i <= 5; i++ {
<-ticker.C
fmt.Printf("第 %d 次触发\n", i)
}
done <- true
}()

// 等待任务完成
<-done
fmt.Println("周期性定时任务完成")
}

基本使用

// 创建周期性定时器 - 每秒触发一次
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop() // 确保结束时停止
for range ticker.C {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}

fmt.Println("周期性定时任务完成")

运行结果如下:

2025-08-19 11:35:57
2025-08-19 11:35:58
2025-08-19 11:35:59
2025-08-19 11:36:00
2025-08-19 11:36:01
2025-08-19 11:36:02
2025-08-19 11:36:03
2025-08-19 11:36:04

使用 time.After 的简化定时器

func afterExample() {
fmt.Println("等待 2 秒...")

// 创建一次性定时器的简化方式
<-time.After(2 * time.Second)
fmt.Println("2 秒后触发!")
}

定时器的高级管理

动态改变定时器频率

func dynamicTicker() {
// 初始频率:1秒
interval := 1 * time.Second
ticker := time.NewTicker(interval)
defer ticker.Stop()

go func() {
count := 0
for {
select {
case t := <-ticker.C:
count++
fmt.Printf("触发 #%d: %s\n", count, t.Format("15:04:05.000"))

// 每触发3次改变频率
if count%3 == 0 {
// 重置定时器
ticker.Stop()

// 增加间隔时间
interval += 500 * time.Millisecond
ticker = time.NewTicker(interval)
fmt.Printf("频率调整为: %.1f秒\n", interval.Seconds())
}
}
}
}()

// 运行10秒后停止
time.Sleep(10 * time.Second)
fmt.Println("动态定时器结束")
}

多个定时器管理

func multipleTimers() {
// 创建多个定时器
timer1 := time.NewTimer(2 * time.Second)
timer2 := time.NewTimer(4 * time.Second)
timer3 := time.NewTimer(6 * time.Second)

// 使用 select 同时监听多个定时器
for i := 0; i < 3; i++ {
select {
case <-timer1.C:
fmt.Println("定时器1触发")
case <-timer2.C:
fmt.Println("定时器2触发")
case <-timer3.C:
fmt.Println("定时器3触发")
}
}
}

带取消功能的定时器

func cancellableTimer() {
// 创建定时器和取消通道
timer := time.NewTimer(5 * time.Second)
cancelChan := make(chan struct{})

// 启动协程处理定时任务
go func() {
select {
case <-timer.C:
fmt.Println("定时任务完成")
case <-cancelChan:
fmt.Println("定时任务已取消")
if !timer.Stop() {
// 如果定时器已触发,清空通道
<-timer.C
}
}
}()

// 模拟用户取消
go func() {
time.Sleep(2 * time.Second)
fmt.Println("用户请求取消")
close(cancelChan)
}()

// 等待足够时间观察结果
time.Sleep(6 * time.Second)
}

定时器使用的最佳实践

正确停止定时器

func stopTimerSafely() {
timer := time.NewTimer(3 * time.Second)

// 在另一个协程中尝试停止
go func() {
time.Sleep(1 * time.Second)
if timer.Stop() {
fmt.Println("定时器已成功停止")
} else {
fmt.Println("定时器已触发,无法停止")
// 清空通道防止阻塞
<-timer.C
}
}()

// 等待定时器触发或停止
select {
case <-timer.C:
fmt.Println("定时器触发")
default:
// 防止阻塞
}

time.Sleep(2 * time.Second)
}

定时器与上下文 (Context) 结合

func timerWithContext() {
ctx, cancel := context.WithCancel(context.Background())

// 创建带超时的上下文
timeoutCtx, _ := context.WithTimeout(ctx, 3*time.Second)

go func() {
select {
case <-timeoutCtx.Done():
fmt.Println("操作超时:", timeoutCtx.Err())
}
}()

// 模拟长时间操作
go func() {
time.Sleep(5 * time.Second)
fmt.Println("长时间操作完成")
}()

// 等待超时发生
time.Sleep(4 * time.Second)
cancel() // 清理资源
}

高性能定时任务

func highPerformanceScheduling() {
// 创建高精度定时器 (100ms)
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()

// 任务队列
taskQueue := make(chan func(), 100)

// 启动工作池
for i := 0; i < 5; i++ {
go func(id int) {
for task := range taskQueue {
start := time.Now()
task()
duration := time.Since(start)
fmt.Printf("Worker %d 完成任务,耗时: %.2fms\n",
id, float64(duration.Microseconds())/1000)
}
}(i)
}

// 定时添加任务
go func() {
for range ticker.C {
taskQueue <- func() {
// 模拟任务执行时间 (0-50ms)
time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
}
}
}()

// 运行一段时间后停止
time.Sleep(5 * time.Second)
fmt.Println("高性能定时任务结束")
}

完整示例程序

package main

import (
"context"
"fmt"
"math/rand"
"time"
)

func main() {
fmt.Println("===== 一次性定时器示例 =====")
timer := time.NewTimer(3 * time.Second)
<-timer.C
fmt.Println("一次性定时器触发\n")

fmt.Println("===== 周期性定时器示例 =====")
tickerExample()

fmt.Println("\n===== 简化定时器示例 =====")
afterExample()

fmt.Println("\n===== 动态频率定时器 =====")
dynamicTicker()
time.Sleep(1 * time.Second) // 确保输出完成

fmt.Println("\n===== 多定时器管理 =====")
multipleTimers()

fmt.Println("\n===== 可取消定时器 =====")
cancellableTimer()
time.Sleep(1 * time.Second) // 确保输出完成

fmt.Println("\n===== 安全停止定时器 =====")
stopTimerSafely()

fmt.Println("\n===== 上下文超时控制 =====")
timerWithContext()
time.Sleep(1 * time.Second) // 确保输出完成

fmt.Println("\n===== 高性能定时任务 =====")
highPerformanceScheduling()
}

// 这里插入前面定义的所有函数...

关键注意事项

  1. 资源泄漏预防

    • 总是使用 defer ticker.Stop() 确保定时器被正确清理
    • 对于停止的 Timer,如果已触发,需要清空通道:if !timer.Stop() { <-timer.C }
  2. 精度问题

    • Go 定时器精度通常为毫秒级
    • 对于高精度需求(>100Hz),考虑专用计时方案
  3. 并发安全

    • Timer 和 Ticker 都是并发安全的
    • 但重置操作(Reset())需要谨慎处理
  4. 性能考虑

    • 避免创建大量短期定时器
    • 对于高频任务,使用单个 Ticker 分发任务
  5. 上下文集成

    • 使用 context.WithTimeout 管理操作超时
    • 在服务关闭时取消所有定时任务