首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 15:18:32 +08:00
commit d6393266b0
193 changed files with 14287 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
Generated
+1
View File
@@ -0,0 +1 @@
bulma
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.codeverse.userSettings.MarscodeWorkspaceAppSettingsState">
<option name="chatAppRouterInfo" value="chat-session" />
<option name="progress" value="1.0" />
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/bulma.iml" filepath="$PROJECT_DIR$/.idea/bulma.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+36
View File
@@ -0,0 +1,36 @@
// bulma/atomic_config.go
package main
import (
"fmt"
"sync/atomic"
"time"
)
// Config 配置结构体(实际项目中可扩展)
type Config struct {
APIURL string // API地址
TimeoutMS int // 超时时间(毫秒)
}
func main() {
var current atomic.Value
// 初始化配置:首次存储需指定类型(推荐存储指针,避免值拷贝)
current.Store(&Config{APIURL: "v1.example.com", TimeoutMS: 1000})
// 后台goroutine:模拟配置热更新(实际场景可从配置中心拉取)
go func() {
time.Sleep(100 * time.Millisecond)
newConf := &Config{APIURL: "v2.example.com", TimeoutMS: 2000}
current.Store(newConf) // 原子替换整个配置
fmt.Println("🔄 配置已热更新!")
}()
// 业务goroutine:持续读取配置(无锁,高效)
for i := 0; i < 5; i++ {
// 类型断言:需与存储类型一致(此处为*Config),否则panic
cfg := current.Load().(*Config)
fmt.Printf("[%d] 当前API: %s, 超时: %dms\n", i, cfg.APIURL, cfg.TimeoutMS)
time.Sleep(50 * time.Millisecond)
}
}
+50
View File
@@ -0,0 +1,50 @@
// bulma/atomic_counter.go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var atomicCounter atomic.Int64 // 原子计数器(新类型)
var muCounter int64 // Mutex保护的计数器
var mu sync.Mutex // 互斥锁
// 原子操作计数
start := time.Now()
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
atomicCounter.Add(1)
}
}()
}
wg.Wait()
atomicTime := time.Since(start)
// Mutex 计数(对比)
start = time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
mu.Lock()
muCounter++
mu.Unlock()
}
}()
}
wg.Wait()
mutexTime := time.Since(start)
fmt.Printf("✅ 原子计数: %d (耗时: %v)\n", atomicCounter.Load(), atomicTime)
fmt.Printf("✅ Mutex计数: %d (耗时: %v)\n", muCounter, mutexTime)
fmt.Printf("🚀 性能提升: %.1fx\n", float64(mutexTime)/float64(atomicTime))
}
+33
View File
@@ -0,0 +1,33 @@
// bulma/atomic_flag.go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var ready atomic.Bool // 就绪标志(原子布尔值)
var wg sync.WaitGroup
// 消费者goroutine:等待标志位变为true后执行
wg.Add(1)
go func() {
defer wg.Done()
// 循环检测标志位,直到变为true(无锁,高效)
for !ready.Load() {
time.Sleep(10 * time.Millisecond)
}
fmt.Println("✅ 消费者检测到 ready=true,开始处理")
}()
// 生产者goroutine:模拟初始化操作,完成后设置标志位
time.Sleep(50 * time.Millisecond) // 模拟初始化耗时
ready.Store(true)
fmt.Println("🔧 生产者设置 ready=true")
wg.Wait()
fmt.Println("所有操作执行完成")
}
+32
View File
@@ -0,0 +1,32 @@
// bulma/atomic_memory_order.go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var relaxedCounter atomic.Uint64 // 无符号原子计数器
var wg sync.WaitGroup
// 使用 Relaxed 顺序(仅保证原子性,无全局顺序约束)
start := time.Now()
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 10000; j++ {
// 第二个参数指定内存顺序:OrderRelaxed(无顺序约束,仅保证原子性)
relaxedCounter.Add(1)
}
}()
}
wg.Wait()
fmt.Printf("✅ Relaxed 计数: %d (耗时: %v)\n",
relaxedCounter.Load(),
time.Since(start))
// 注意:最终值正确,但中间状态可能"乱序"被其他 goroutine 观察到
}
+50
View File
@@ -0,0 +1,50 @@
// bulma/atomic_mutex_hybrid.go
package main
import (
"fmt"
"sync"
"sync/atomic"
)
// RequestCounter 请求计数器(混合方案:原子操作+Mutex)
type RequestCounter struct {
total atomic.Uint64 // 高频累加,用原子操作
mu sync.Mutex // 互斥锁,保护复杂数据结构(map)
details map[string]uint64 // 复杂结构,用 Mutex 保护
}
// Inc 累加请求数:包含高频简单操作与复杂结构更新
func (rc *RequestCounter) Inc(endpoint string) {
rc.total.Add(1) // 无锁累加总数
// 复杂数据结构更新(map写入),通过加锁保护,避免数据竞争
rc.mu.Lock()
rc.details[endpoint]++
rc.mu.Unlock()
}
// Stats 获取统计结果:通过深拷贝,避免外部修改内部数据
func (rc *RequestCounter) Stats() (uint64, map[string]uint64) {
rc.mu.Lock()
defer rc.mu.Unlock()
// 深拷贝避免外部修改
copyDetails := make(map[string]uint64, len(rc.details))
for k, v := range rc.details {
copyDetails[k] = v
}
return rc.total.Load(), copyDetails
}
func main() {
rc := &RequestCounter{details: make(map[string]uint64)}
// 模拟3次接口请求
rc.Inc("/api/users")
rc.Inc("/api/posts")
rc.Inc("/api/users")
// 查看统计结果
total, details := rc.Stats()
fmt.Printf("✅ 总请求数: %d\n", total)
fmt.Printf("✅ 详情: %+v\n", details)
}
+29
View File
@@ -0,0 +1,29 @@
// bulma/atomic_pointer.go
package main
import (
"fmt"
"sync/atomic"
)
type Node struct {
Value int
Next *Node
}
func main() {
var head atomic.Pointer[Node]
head.Store(&Node{Value: 10})
// 原子替换头节点
old := head.Swap(&Node{Value: 20})
fmt.Printf("✅ 旧头节点值: %d\n", old.Value)
fmt.Printf("✅ 新头节点值: %d\n", head.Load().Value)
// CAS 安全更新(仅当当前值为预期时才更新)
if head.CompareAndSwap(&Node{Value: 20}, &Node{Value: 30}) {
fmt.Println("✅ CAS 成功:头节点更新为 30")
} else {
fmt.Println("❌ CAS 失败:头节点已被其他 goroutine 修改")
}
}
+50
View File
@@ -0,0 +1,50 @@
// bulma/atomic_spinlock.go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
// SpinLock 自旋锁结构体(基于atomic.Bool实现)
type SpinLock struct {
flag atomic.Bool // false=未锁定,true=已锁定
}
// Lock 加锁:自旋等待,直到获取锁
func (l *SpinLock) Lock() {
// CAS逻辑:尝试将flag从false改为true,失败则循环重试
for l.flag.CompareAndSwap(false, true) {
// 短暂休眠,避免忙等耗尽CPU(关键优化)
time.Sleep(time.Nanosecond) // 避免忙等耗尽 CPU
}
}
// Unlock 解锁:将flag设为false,释放锁
func (l *SpinLock) Unlock() {
l.flag.Store(false)
}
func main() {
var lock SpinLock
var counter atomic.Int32 // 原子计数器,配合自旋锁使用
var wg sync.WaitGroup
// 10 个 goroutine 争抢自旋锁
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
lock.Lock() // 获取自旋锁
defer lock.Unlock() // 延迟解锁,避免锁泄露
counter.Add(1)
fmt.Printf("Goroutine %d 完成计数\n", id)
}(i)
}
wg.Wait()
fmt.Printf("✅ 最终计数: %d (应为 10)\n", counter.Load())
}
+64
View File
@@ -0,0 +1,64 @@
// bulma/atomic_stack.go
package main
import (
"fmt"
"sync/atomic"
)
// StackNode 无锁栈节点(泛型,支持任意数据类型)
type StackNode[T any] struct {
Value T
Next *StackNode[T] // 指向栈底节点
}
// LockFreeStack 无锁栈(基于atomic.Pointer实现)
type LockFreeStack[T any] struct {
head atomic.Pointer[StackNode[T]] // 栈顶指针(原子指针)
}
// Push 入栈:通过CAS操作替换栈顶,保证并发安全
func (s *LockFreeStack[T]) Push(val T) {
for {
oldHead := s.head.Load()
newHead := &StackNode[T]{Value: val, Next: oldHead}
// CAS操作成功则入栈完成,失败则重试(避免并发冲突)
if s.head.CompareAndSwap(oldHead, newHead) {
return // CAS 成功,退出
}
// CAS 失败(被其他 goroutine 修改),重试
}
}
// Pop 出栈:通过CAS操作替换栈顶为下一个节点,无元素时返回false
func (s *LockFreeStack[T]) Pop() (T, bool) {
for {
oldHead := s.head.Load()
if oldHead == nil {
var zero T // 空值,对应泛型默认零值
return zero, false
}
// CAS操作成功则出栈完成,返回栈顶元素
if s.head.CompareAndSwap(oldHead, oldHead.Next) {
return oldHead.Value, true
}
}
}
func main() {
stack := &LockFreeStack[int]{}
// 入栈3个元素(10、20、30
stack.Push(10)
stack.Push(20)
stack.Push(30)
// 出栈(LIFO:后进先出,依次弹出30、20、10)
for i := 0; i < 3; i++ {
if val, ok := stack.Pop(); ok {
fmt.Printf("✅ 弹出: %d\n", val)
}
}
// 空栈测试:弹出操作失败
if _, ok := stack.Pop(); !ok {
fmt.Println("栈已为空,弹出失败")
}
}
+47
View File
@@ -0,0 +1,47 @@
// bulma/atomic_stress_test_demo.go
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
func main() {
var counter atomic.Uint64
var wg sync.WaitGroup
// 压力测试配置:10000个goroutine,每个累加1000次,总计1亿次操作
goroutineNum := 10000
perGoroutineOps := 1000
wg.Add(goroutineNum)
start := time.Now()
for i := 0; i < goroutineNum; i++ {
go func() {
defer wg.Done()
for j := 0; j < perGoroutineOps; j++ {
counter.Add(1) // 默认使用OrderSeqCst,安全稳定
}
}()
}
wg.Wait()
cost := time.Since(start)
expected := uint64(goroutineNum * perGoroutineOps)
actual := counter.Load()
// 验证结果:判断实际计数与预期计数是否一致,验证原子操作稳定性
fmt.Printf("压力测试完成:%d个goroutine,每个执行%d次累加\n", goroutineNum, perGoroutineOps)
fmt.Printf("预期计数: %d\n", expected)
fmt.Printf("实际计数: %d\n", actual)
fmt.Printf("执行耗时: %v\n", cost)
fmt.Printf("操作吞吐量: %.2f万次/毫秒\n", float64(expected)/float64(cost.Milliseconds()))
if actual == expected {
fmt.Println("原子操作稳定可靠,无数据竞争!")
} else {
fmt.Printf("原子操作异常,计数偏差: %d\n", expected-actual)
}
}
+21
View File
@@ -0,0 +1,21 @@
// bulma/atomic_value_trap.go
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var v atomic.Value
v.Store("initial string") // 首次存储 string
// ❌ 错误:尝试存储不同类型的值(会 panic!)
defer func() {
if r := recover(); r != nil {
fmt.Println("⚠️ 捕获 panic:", r)
fmt.Println("✅ 正确做法:始终存储相同类型(推荐指针)")
}
}()
v.Store(123) // 运行时 panic: sync/atomic: store of inconsistently typed value into Value
}
+26
View File
@@ -0,0 +1,26 @@
package main
import "fmt"
func main() {
var isSuccess bool
fmt.Printf("布尔零值: %t\n", isSuccess) // 输出false
a, b := true, false
// 逻辑运算
fmt.Printf("a && b: %t\n", a && b) // false(与)
fmt.Printf("a || b: %t\n", a || b) // true(或)
fmt.Printf("!a: %t\n", !a) // false(非)
// 条件判断中使用
score := 85
isPass := score >= 60
if isPass {
fmt.Println("考试通过") // 输出此句
}
// 错误示例(编译不通过)
// var b bool = 1 // 报错:cannot use 1 (untyped int constant) as bool value in variable declaration
// fmt.Println(b + 1) // 报错:invalid operation: b + 1 (mismatched types bool and untyped int)
}
+53
View File
@@ -0,0 +1,53 @@
package main
import (
"fmt"
"math"
"unsafe"
)
func main() {
// 整数类型
var maxInt8 int8 = 127
var minInt8 int8 = -128
fmt.Printf("int8范围: %d ~ %d\n", minInt8, maxInt8)
// 字节与Unicode码点
var b byte = 0x61 // 十六进制表示字符'a'
var r rune = '中' // Unicode码点,值为20013
fmt.Printf("byte('a'): %T=%d(字符:%c\n", b, b, b) // uint8=97(字符:a
fmt.Printf("rune('中'): %T=%d(字符:%c\n", r, r, r) // int32=20013(字符:中)
// uintptr与指针(底层内存操作,谨慎使用)
var x int = 100
p := &x // *int类型,存储x的地址
ptrVal := uintptr(unsafe.Pointer(p)) // 转换为存储地址的数值
fmt.Printf("x的地址:%p → uintptr%x\n", p, ptrVal)
// 浮点数
f32 := float32(3.1415926535)
f64 := 3.141592653589793 // 默认float64
fmt.Printf("float32: %.6f, float64: %.12f\n", f32, f64)
// 复数
c := complex(3, 4) // 等价于3+4icomplex128
fmt.Printf("复数:%v,实部:%v,虚部:%v\n", c, real(c), imag(c)) // (3+4i) 3 4
// 复数运算
var d complex128 = 1 - 2i
fmt.Printf("c+d: %v, c*d: %v\n", c+d, c*d) // 输出4+2i, 11-2i
// 复数相等判断
if real(c) == real(d) && imag(c) == imag(d) {
fmt.Println("c与d相等")
} else {
fmt.Println("c与d不相等")
}
// 浮点数比较(考虑精度)
if math.Abs(f64-float64(f32)) < 1e-6 {
fmt.Println("浮点数近似相等")
} else {
fmt.Println("浮点数不相等")
}
}
+45
View File
@@ -0,0 +1,45 @@
package main
import (
"fmt"
"strings"
)
func main() {
// 字符串初始化
s1 := "Golang语言"
s2 := `多行字符串,
小猫:喵喵喵,
小狗:汪汪汪`
fmt.Println("s1:", s1)
fmt.Println("s2:", s2)
// 字符串长度(字节数)
fmt.Printf("s1长度(字节): %d\n", len(s1)) // 输出12"Golang"6字节 + "语言"6字节)
// 字符串遍历(for vs for range
fmt.Println("for遍历(按byte:")
for i := 0; i < len(s1); i++ {
fmt.Printf("%x ", s1[i]) // 输出字节的十六进制,中文会拆分为多字节
}
fmt.Println("\nfor range遍历(按rune:")
for _, r := range s1 {
fmt.Printf("%c ", r) // 输出完整字符:G o l a n g 语 言
}
// 字符串修改(需转[]rune
s3 := "hello"
runes := []rune(s3)
runes[0] = 'H'
s3 = string(runes)
fmt.Printf("\n修改后: %s\n", s3) // 输出Hello
// 高效字符串拼接
var builder strings.Builder
for i := 0; i < 5; i++ {
builder.WriteString(fmt.Sprintf("part%d", i))
}
fmt.Println("拼接结果:", builder.String()) // part0part1part2part3part4
}
+1000
View File
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// 打开文件(创建+追加模式)
file, err := os.OpenFile("batch_write.log",
os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("文件打开失败:%v\n", err)
return
}
defer file.Close()
// 初始化4KB缓冲区(默认4096字节,可按场景调整)
writer := bufio.NewWriterSize(file, 4096)
defer writer.Flush() // 退出前确保缓冲区数据写入文件
// 批量写入1000条记录
for i := 0; i < 1000; i++ {
fmt.Fprintf(writer, "批量记录%d%s\n",
i, "这是一条批量写入的数据")
}
fmt.Println("批量写入完成,缓冲区数据将由defer自动Flush")
}
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"fmt"
"strings"
"time"
)
func main() {
const loopCount = 100000 // 10万次拼接
var builder strings.Builder
// 预分配内存(预估每个item占10字节,避免动态扩容)
builder.Grow(loopCount * 10)
start := time.Now()
for i := 0; i < loopCount; i++ {
fmt.Fprintf(&builder, "item_%d,", i) // 直接写入缓冲区,无临时字符串
}
result := builder.String()
fmt.Printf("strings.Builder拼接耗时:%v\n", time.Since(start))
_ = result // 避免未使用变量警告
}
+18
View File
@@ -0,0 +1,18 @@
package main
import (
"fmt"
"time"
)
func main() {
const loopCount = 100000 // 10万次拼接
var result string
start := time.Now()
for i := 0; i < loopCount; i++ {
result += fmt.Sprintf("item_%d,", i) // 每次拼接生成新字符串,内存分配频繁
}
fmt.Printf("fmt循环拼接耗时:%v\n", time.Since(start))
_ = result // 避免未使用变量警告
}
+108
View File
@@ -0,0 +1,108 @@
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
// =============== ABA 问题演示(增强时序稳定性) ===============
func demoABAProblem() {
var value int32 = 100
var wg sync.WaitGroup
ready := make(chan struct{}) // 同步信号:确保 A 先读取
wg.Add(2)
// Goroutine A: 读取初始值后等待信号
go func() {
defer wg.Done()
old := atomic.LoadInt32(&value) // 读取到 100
<-ready // 等待 B 完成 ABA 修改
if atomic.CompareAndSwapInt32(&value, old, 200) {
fmt.Println("⚠️ ABA 问题触发: CAS 成功!但值曾被篡改 (100→150→100)")
} else {
fmt.Println("❌ 未复现 ABA(调度异常)")
}
}()
// Goroutine B: 执行 A→B→A 修改
go func() {
defer wg.Done()
time.Sleep(5 * time.Millisecond) // 确保 A 已读取
atomic.StoreInt32(&value, 150) // A→B
atomic.StoreInt32(&value, 100) // B→A
close(ready) // 通知 A 执行 CAS
}()
wg.Wait()
fmt.Printf("最终值: %d (ABA 发生时应为 200)\n", value)
}
// =============== 安全方案:位域编码防 ABA ===============
// 64位结构: [高32位: 版本号] | [低32位: 实际值]
type VersionedInt32 struct {
data int64 // 原子存储单元
}
// 合并值与版本号
func pack(val, ver int32) int64 {
return (int64(ver) << 32) | int64(uint32(val))
}
// 拆解:返回 (值, 版本号)
func unpack(data int64) (val int32, ver int32) {
return int32(data), int32(data >> 32) // 低32位=值, 高32位=版本
}
// 安全读取当前值
func (v *VersionedInt32) Load() int32 {
val, _ := unpack(atomic.LoadInt64(&v.data)) // 取第一个返回值
return val
}
// 带版本号的原子 CAS(彻底规避 ABA)
func (v *VersionedInt32) CAS(oldVal, newVal int32) bool {
for {
current := atomic.LoadInt64(&v.data)
curVal, curVer := unpack(current)
if curVal != oldVal {
return false // 值已变更,拒绝更新
}
// 构造新状态:值更新 + 版本号+1
newState := pack(newVal, curVer+1)
if atomic.CompareAndSwapInt64(&v.data, current, newState) {
return true
}
// 失败则重试
}
}
func main() {
fmt.Println("=== ABA 问题演示(通道同步确保时序) ===")
demoABAProblem()
fmt.Println("\n=== 安全方案验证(位域编码) ===")
vv := &VersionedInt32{data: pack(100, 0)} // 初始值=100, 版本=0
// 首次 CAS100 → 200
if vv.CAS(100, 200) {
val := vv.Load()
_, ver := unpack(atomic.LoadInt64(&vv.data))
fmt.Printf("✅ CAS 成功 | 值: %d, 版本: %d\n", val, ver)
}
// 尝试用过期旧值 100 更新(应失败)
if !vv.CAS(100, 300) {
fmt.Println("✅ 检测到非法修改:CAS 拒绝使用过期旧值更新")
}
// 使用当前正确值更新
if vv.CAS(200, 300) {
fmt.Printf("✅ 安全更新成功 | 当前值: %d\n", vv.Load())
}
}
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var counter int64
var wg sync.WaitGroup
const goroutines, increments = 10, 10000
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < increments; j++ {
for {
old := atomic.LoadInt64(&counter)
if atomic.CompareAndSwapInt64(&counter, old, old+1) {
break // 成功则退出重试循环
}
// 失败:其他 goroutine 已修改,重试
}
}
}()
}
wg.Wait()
fmt.Printf("✅ 最终计数值: %d (期望: %d)\n", counter, goroutines*increments)
}
+77
View File
@@ -0,0 +1,77 @@
package main
import (
"fmt"
"sync"
"sync/atomic"
"unsafe"
)
type node struct {
value interface{}
next unsafe.Pointer
}
type LockFreeStack struct {
top unsafe.Pointer
}
func (s *LockFreeStack) Push(v interface{}) {
newNode := &node{value: v}
for {
oldTop := atomic.LoadPointer(&s.top)
newNode.next = oldTop
if atomic.CompareAndSwapPointer(&s.top, oldTop, unsafe.Pointer(newNode)) {
break
}
}
}
func (s *LockFreeStack) Pop() (interface{}, bool) {
for {
oldTop := atomic.LoadPointer(&s.top)
if oldTop == nil {
return nil, false // 栈空:返回 false
}
node := (*node)(oldTop)
if atomic.CompareAndSwapPointer(&s.top, oldTop, node.next) {
return node.value, true // 弹出成功:返回 true
}
}
}
func main() {
stack := &LockFreeStack{}
var wg sync.WaitGroup
const ops = 1000
wg.Add(2)
// 生产者:压入 1000 个元素
go func() {
defer wg.Done()
for i := 0; i < ops; i++ {
stack.Push(i)
}
}()
// 消费者:弹出 1000 个元素
go func() {
defer wg.Done()
count := 0
for count < ops {
if _, ok := stack.Pop(); ok {
count++
}
}
}()
wg.Wait()
// 🔑 核心修正:验证栈是否为空
_, popped := stack.Pop() // popped = true 表示"成功弹出"(栈非空)
if !popped { // !popped = true 表示"弹出失败"(栈已空)✅
fmt.Println("✅ 无锁栈验证通过:所有元素正确入栈出栈,栈已空")
} else {
fmt.Println("❌ 栈非空,存在数据不一致(验证逻辑已修正)")
}
}
+121
View File
@@ -0,0 +1,121 @@
package main
import (
"fmt"
"sync"
"time"
)
// ===================== 一、Channel 类型系统 =====================
// producer 只写通道 生产者
func producer(ch chan<- int) {
defer close(ch) // 延迟关闭,确保数据发送完毕
for i := 1; i <= 2; i++ {
ch <- i * 10
}
}
// consumer 只读通道 消费者
func consumer(ch <-chan int) {
for data := range ch {
fmt.Printf("消费数据:%d\n", data)
}
}
// ===================== 二、Channel 缓冲策略 =====================
func bufferDemo() {
fmt.Println("\n===== 无缓冲通道(同步通信)=====")
unbufCh := make(chan string)
go func() {
unbufCh <- "同步通道数据"
}()
fmt.Println(<-unbufCh)
fmt.Println("\n===== 有缓冲通道(异步通信)=====")
bufCh := make(chan int, 3)
bufCh <- 1
bufCh <- 2
// 监控缓冲状态
fmt.Printf("已缓存数据:%d,总缓冲容量:%d\n", len(bufCh), cap(bufCh))
close(bufCh)
for v := range bufCh {
fmt.Println("异步数据:", v)
}
}
// ===================== 三、Channel 安全关闭 =====================
func closeDemo() {
fmt.Println("\n===== 通道安全关闭演示=====")
ch := make(chan int, 2)
// 保证通道仅关闭一次
var closeOnce sync.Once
go func() {
closeOnce.Do(func() {
ch <- 100
ch <- 200
close(ch)
fmt.Println("通道已安全关闭")
})
}()
// 安全读取数据
for {
val, ok := <-ch
if !ok {
fmt.Println("通道关闭,读取结束")
break
}
fmt.Printf("读取值:%d\n", val)
}
}
// ===================== 四、Channel 高级用法 =====================
func advancedDemo() {
fmt.Println("\n===== select 多路复用=====")
ch1, ch2 := make(chan string), make(chan string)
// 模拟异步任务
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "任务1执行完成"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "任务2执行完成"
}()
// 监听多个通道
for i := 0; i < 2; i++ {
select {
case msg := <-ch1:
fmt.Println(msg)
case msg := <-ch2:
fmt.Println(msg)
}
}
// 非阻塞读取
fmt.Println("\n===== 非阻塞通道读取=====")
ch := make(chan int, 1)
select {
case val := <-ch:
fmt.Println("读取到数据:", val)
default:
fmt.Println("通道暂无数据,非阻塞跳过")
}
}
// ===================== 主函数 =====================
func main() {
fmt.Println("===== 一、Channel 类型系统演示=====")
ch := make(chan int)
go producer(ch)
consumer(ch)
// 执行所有演示
bufferDemo()
closeDemo()
advancedDemo()
}
Binary file not shown.
+39
View File
@@ -0,0 +1,39 @@
package main
import "fmt"
func printArray(a [3]int) {
fmt.Println("函数内数组:", a)
a[0] = 0 // 不会影响原数组
}
func main() {
// 数组初始化
var arr1 [3]int // 长度为3的int数组,零值初始化
arr2 := [4]string{"a", "b", "c"} // 部分初始化,未指定的元素为零值
arr3 := [...]int{10, 20, 30, 40} // 长度由初始化元素数量决定
fmt.Println("arr1:", arr1) // [0 0 0]
fmt.Println("arr2:", arr2) // [a b c ]
fmt.Println("arr3长度:", len(arr3)) // 4
// 数组访问与修改
arr1[0] = 100
arr1[1] = 200
fmt.Println("arr1修改后:", arr1) // [100 200 0]
// 数组比较(元素类型可比较时)
arr4 := [3]int{100, 200, 0}
if arr1 == arr4 {
fmt.Println("arr1与arr4相等")
}
// 数组是值类型
arr5 := arr1
arr5[2] = 300
fmt.Println("arr1:", arr1) // [100 200 0],未被修改
fmt.Println("arr5:", arr5) // [100 200 300]
// 数组作为函数参数
printArray(arr1)
}
+61
View File
@@ -0,0 +1,61 @@
package main
/*import (
"fmt"
"sync"
)
// 工作函数,演示通道作为信号量
func worker(id int, sem chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
// 获取信号量
sem <- struct{}{}
defer func() { <-sem }() // 释放信号量
fmt.Printf("Worker %d 开始工作\n", id)
// 模拟工作
for i := 0; i < 3; i++ {
fmt.Printf("Worker %d 工作中...\n", id)
}
fmt.Printf("Worker %d 完成工作\n", id)
}
func main() {
// 带缓冲通道(容量2
chBuffered := make(chan int, 2)
chBuffered <- 1 // 发送不阻塞(未达容量)
chBuffered <- 2
fmt.Println(<-chBuffered) // 接收:1
fmt.Println(<-chBuffered) // 接收:2
close(chBuffered)
// 关闭后发送会panic,接收返回零值
if v, ok := <-chBuffered; ok {
fmt.Println(v)
} else {
fmt.Println("通道已关闭") // 输出此句
}
// 无缓冲通道(发送/接收需同时就绪)
chUnbuffered := make(chan string)
go func() {
chUnbuffered <- "hello from goroutine" // 发送方:等待接收
}()
msg := <-chUnbuffered // 接收方:等待发送
fmt.Println(msg) // 输出:hello from goroutine
close(chUnbuffered)
// 通道实现信号量(限制并发数)
var wg sync.WaitGroup
sem := make(chan struct{}, 2) // 并发数限制为2
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, sem, &wg)
}
wg.Wait()
close(sem)
fmt.Println("所有工作完成")
}
*/
+78
View File
@@ -0,0 +1,78 @@
package main
import (
"fmt"
"math"
"sync"
)
func main() {
// 映射创建
m1 := make(map[string]int) // make创建
m2 := map[string]int{ // 字面量初始化
"apple": 5,
"banana": 3,
}
// 添加和修改元素
m1["orange"] = 2
m2["apple"] = 6 // 修改已有键的值
// 访问元素
fmt.Println("m1[orange]:", m1["orange"]) // 2
fmt.Println("m2[banana]:", m2["banana"]) // 3
// 判断键是否存在
v, ok := m2["orange"]
if ok {
fmt.Printf("orange count: %d\n", v)
} else {
fmt.Println("orange not found") // 输出该结果
}
// 删除元素
delete(m2, "banana")
fmt.Println("删除后m2[banana]:", m2["banana"]) // 0(零值)
// 映射长度
fmt.Println("m2长度:", len(m2)) // 1
// 映射遍历(无序)
fmt.Println("map遍历:")
for fruit, count := range m2 {
fmt.Printf("%s: %d\n", fruit, count) // 顺序不固定
}
// 映射的键类型限制
var m3 map[int]string // 整数
var m4 map[string]bool // 字符串
var m5 map[bool]int // 布尔值
var m6 map[[3]int]string // 数组(元素类型也必须可比较)
// 结构体作为键(所有字段都必须可比较)
type Point struct {
X, Y int
}
var m7 map[Point]string
fmt.Printf("m3:%T, m4:%T, m5:%T\n", m3, m4, m5)
fmt.Printf("m6:%T, m7:%T\n", m6, m7)
// 特殊情况:NaN作为键(每个NaN都是唯一的)
m := map[float64]string{}
nan1 := math.NaN()
nan2 := math.NaN()
m[nan1] = "first"
m[nan2] = "second"
fmt.Println("NaN映射长度:", len(m)) // 2
// 并发安全映射(sync.Map
var m8 sync.Map
m8.Store("cat", 2) // 存储键值对
m8.Store("dog", 1)
// 读取与删除
if v, ok := m8.Load("cat"); ok {
fmt.Printf("cat count: %d\n", v) // 输出2
}
m8.Delete("dog")
}
+43
View File
@@ -0,0 +1,43 @@
package main
import "fmt"
// 函数传指针,修改外部变量
func increment(x *int) {
*x++
}
// 指针作为返回值
func createInt() *int {
var num int = 100
return &num
}
func main() {
var x int = 20
var p *int = &x // p是指向x的指针
fmt.Printf("x的值: %d, x的地址: %p\n", x, &x)
fmt.Printf("p的值(地址): %p, p指向的值: %d\n", p, *p)
// 通过指针修改值
*p = 21
fmt.Printf("修改后x的值: %d\n", x) // 输出21
// 函数传指针
increment(&x)
fmt.Printf("increment后x值: %d\n", x) // 输出22
// 指针作为返回值
p2 := createInt()
fmt.Printf("createInt返回值: %d, 地址: %p\n", *p2, p2) // 输出100及地址
// 指针与nil比较
var p3 *int
if p3 == nil {
fmt.Println("p3是nil指针")
}
// 错误示例(编译不通过)
// p++ // 报错:invalid operation: p++ (non-numeric type *int)
}
+37
View File
@@ -0,0 +1,37 @@
package main
import "fmt"
func main() {
// 切片创建
s1 := []int{1, 2, 3} // 直接初始化
s2 := make([]int, 3, 5) // make创建,长度3,容量5
s3 := make([]int, 3) // 容量默认等于长度
fmt.Printf("s1: %v, len=%d, cap=%d\n", s1, len(s1), cap(s1)) // [1 2 3] 3 3
fmt.Printf("s2: %v, len=%d, cap=%d\n", s2, len(s2), cap(s2)) // [0 0 0] 3 5
fmt.Printf("s3: %v, len=%d, cap=%d\n", s3, len(s3), cap(s3)) // [0 0 0] 3 3
// 切片操作
s4 := s1[1:3] // 切片表达式,从索引1到3(不包含3)
fmt.Println("s4:", s4) // [2 3]
// 修改切片元素(影响底层数组)
s4[0] = 20
fmt.Println("修改后s1:", s1) // [1 20 3]
fmt.Println("修改后s4:", s4) // [20 3]
// 切片追加元素
s2 = append(s2, 400) // len=4 == cap=5 → 不扩容
fmt.Printf("添加400后s2: %v, len=%d, cap=%d\n", s2, len(s2), cap(s2)) // [0 0 0 400] 4 5
s2 = append(s2, 500) // len=5 == cap=5 → 不扩容
fmt.Printf("添加500后s2: %v, len=%d, cap=%d\n", s2, len(s2), cap(s2)) // [0 0 0 400 500] 5 5
s2 = append(s2, 600) // len=6 > cap=5 → 扩容(容量变为10)
fmt.Printf("添加600后s2: %v, len=%d, cap=%d\n", s2, len(s2), cap(s2)) // [0 0 0 400 500 600] 6 10
// 复制切片
dst := make([]int, 2)
src := []int{10, 20, 30}
copied := copy(dst, src) // 复制2个元素(取len(dst)和len(src)的最小值)
fmt.Printf("复制后dst: %v, 复制数量: %d\n", dst, copied) // [10 20] 2
}
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"encoding/json"
"fmt"
)
// 嵌套结构体(地址信息)
type Address struct {
City string
Street string
}
// 主结构体(用户信息)
type User struct {
ID int
Name string
Age int
Address // 嵌套结构体(匿名字段,可直接访问其字段)
}
// 带标签的结构体
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
}
// 结构体方法
func (u *User) GetInfo() string {
return fmt.Sprintf("User: %s, Age: %d, City: %s", u.Name, u.Age, u.City)
}
func main() {
// 初始化带嵌套的结构体
u := User{
ID: 1,
Name: "Alice",
Age: 20,
Address: Address{
City: "Beijing",
Street: "Main St",
},
}
// 访问字段(嵌套字段可直接访问)
fmt.Printf("用户:%+v\n", u)
fmt.Println("城市:", u.City) // 等价于u.Address.City
fmt.Println("用户信息:", u.GetInfo())
// 结构体是值类型:赋值时复制所有字段(包括嵌套字段)
u2 := u
u2.Age = 21
u2.Street = "New St"
fmt.Println("u年龄:", u.Age, "u2年龄:", u2.Age) // 20 21
fmt.Println("u街道:", u.Street, "u2街道:", u2.Street) // Main St New St
// 结构体比较
p1 := Person{Name: "Alice", Age: 25}
p2 := Person{Name: "Alice", Age: 25}
if p1 == p2 {
fmt.Println("p1与p2相等")
}
// 结构体标签:JSON序列化
jsonP, _ := json.Marshal(p1)
fmt.Printf("Person JSON: %s\n", jsonP) // 输出{"name":"Alice","age":25}
p3 := Person{Name: "Bob"} // Age为零值0
jsonP3, _ := json.Marshal(p3)
fmt.Printf("p3 JSON: %s\n", jsonP3) // 输出{"name":"Bob"}Age为0被omitempty忽略)
}
+100
View File
@@ -0,0 +1,100 @@
[2025-10-31 18:24:38] goroutine9:完成第0条任务
[2025-10-31 18:24:38] goroutine9:完成第1条任务
[2025-10-31 18:24:38] goroutine9:完成第2条任务
[2025-10-31 18:24:38] goroutine9:完成第3条任务
[2025-10-31 18:24:38] goroutine9:完成第4条任务
[2025-10-31 18:24:38] goroutine9:完成第5条任务
[2025-10-31 18:24:38] goroutine9:完成第6条任务
[2025-10-31 18:24:38] goroutine9:完成第7条任务
[2025-10-31 18:24:38] goroutine9:完成第8条任务
[2025-10-31 18:24:38] goroutine9:完成第9条任务
[2025-10-31 18:24:38] goroutine4:完成第0条任务
[2025-10-31 18:24:38] goroutine4:完成第1条任务
[2025-10-31 18:24:38] goroutine4:完成第2条任务
[2025-10-31 18:24:38] goroutine4:完成第3条任务
[2025-10-31 18:24:38] goroutine2:完成第0条任务
[2025-10-31 18:24:38] goroutine3:完成第0条任务
[2025-10-31 18:24:38] goroutine1:完成第0条任务
[2025-10-31 18:24:38] goroutine6:完成第0条任务
[2025-10-31 18:24:38] goroutine0:完成第0条任务
[2025-10-31 18:24:38] goroutine5:完成第0条任务
[2025-10-31 18:24:38] goroutine7:完成第0条任务
[2025-10-31 18:24:38] goroutine8:完成第0条任务
[2025-10-31 18:24:38] goroutine2:完成第1条任务
[2025-10-31 18:24:38] goroutine2:完成第2条任务
[2025-10-31 18:24:38] goroutine2:完成第3条任务
[2025-10-31 18:24:38] goroutine2:完成第4条任务
[2025-10-31 18:24:38] goroutine2:完成第5条任务
[2025-10-31 18:24:38] goroutine5:完成第1条任务
[2025-10-31 18:24:38] goroutine5:完成第2条任务
[2025-10-31 18:24:38] goroutine5:完成第3条任务
[2025-10-31 18:24:38] goroutine5:完成第4条任务
[2025-10-31 18:24:38] goroutine5:完成第5条任务
[2025-10-31 18:24:38] goroutine5:完成第6条任务
[2025-10-31 18:24:38] goroutine5:完成第7条任务
[2025-10-31 18:24:38] goroutine5:完成第8条任务
[2025-10-31 18:24:38] goroutine5:完成第9条任务
[2025-10-31 18:24:38] goroutine4:完成第4条任务
[2025-10-31 18:24:38] goroutine4:完成第5条任务
[2025-10-31 18:24:38] goroutine4:完成第6条任务
[2025-10-31 18:24:38] goroutine4:完成第7条任务
[2025-10-31 18:24:38] goroutine4:完成第8条任务
[2025-10-31 18:24:38] goroutine4:完成第9条任务
[2025-10-31 18:24:38] goroutine2:完成第6条任务
[2025-10-31 18:24:38] goroutine2:完成第7条任务
[2025-10-31 18:24:38] goroutine2:完成第8条任务
[2025-10-31 18:24:38] goroutine2:完成第9条任务
[2025-10-31 18:24:38] goroutine1:完成第1条任务
[2025-10-31 18:24:38] goroutine1:完成第2条任务
[2025-10-31 18:24:38] goroutine1:完成第3条任务
[2025-10-31 18:24:38] goroutine1:完成第4条任务
[2025-10-31 18:24:38] goroutine1:完成第5条任务
[2025-10-31 18:24:38] goroutine1:完成第6条任务
[2025-10-31 18:24:38] goroutine1:完成第7条任务
[2025-10-31 18:24:38] goroutine1:完成第8条任务
[2025-10-31 18:24:38] goroutine1:完成第9条任务
[2025-10-31 18:24:38] goroutine7:完成第1条任务
[2025-10-31 18:24:38] goroutine7:完成第2条任务
[2025-10-31 18:24:38] goroutine7:完成第3条任务
[2025-10-31 18:24:38] goroutine7:完成第4条任务
[2025-10-31 18:24:38] goroutine7:完成第5条任务
[2025-10-31 18:24:38] goroutine7:完成第6条任务
[2025-10-31 18:24:38] goroutine7:完成第7条任务
[2025-10-31 18:24:38] goroutine7:完成第8条任务
[2025-10-31 18:24:38] goroutine7:完成第9条任务
[2025-10-31 18:24:38] goroutine8:完成第1条任务
[2025-10-31 18:24:38] goroutine8:完成第2条任务
[2025-10-31 18:24:38] goroutine8:完成第3条任务
[2025-10-31 18:24:38] goroutine8:完成第4条任务
[2025-10-31 18:24:38] goroutine8:完成第5条任务
[2025-10-31 18:24:38] goroutine8:完成第6条任务
[2025-10-31 18:24:38] goroutine8:完成第7条任务
[2025-10-31 18:24:38] goroutine8:完成第8条任务
[2025-10-31 18:24:38] goroutine8:完成第9条任务
[2025-10-31 18:24:38] goroutine3:完成第1条任务
[2025-10-31 18:24:38] goroutine3:完成第2条任务
[2025-10-31 18:24:38] goroutine3:完成第3条任务
[2025-10-31 18:24:38] goroutine3:完成第4条任务
[2025-10-31 18:24:38] goroutine3:完成第5条任务
[2025-10-31 18:24:38] goroutine3:完成第6条任务
[2025-10-31 18:24:38] goroutine3:完成第7条任务
[2025-10-31 18:24:38] goroutine3:完成第8条任务
[2025-10-31 18:24:38] goroutine3:完成第9条任务
[2025-10-31 18:24:38] goroutine6:完成第1条任务
[2025-10-31 18:24:38] goroutine6:完成第2条任务
[2025-10-31 18:24:38] goroutine6:完成第3条任务
[2025-10-31 18:24:38] goroutine6:完成第4条任务
[2025-10-31 18:24:38] goroutine6:完成第5条任务
[2025-10-31 18:24:38] goroutine6:完成第6条任务
[2025-10-31 18:24:38] goroutine6:完成第7条任务
[2025-10-31 18:24:38] goroutine6:完成第8条任务
[2025-10-31 18:24:38] goroutine6:完成第9条任务
[2025-10-31 18:24:38] goroutine0:完成第1条任务
[2025-10-31 18:24:38] goroutine0:完成第2条任务
[2025-10-31 18:24:38] goroutine0:完成第3条任务
[2025-10-31 18:24:38] goroutine0:完成第4条任务
[2025-10-31 18:24:38] goroutine0:完成第5条任务
[2025-10-31 18:24:38] goroutine0:完成第6条任务
[2025-10-31 18:24:38] goroutine0:完成第7条任务
[2025-10-31 18:24:38] goroutine0:完成第8条任务
[2025-10-31 18:24:38] goroutine0:完成第9条任务
+68
View File
@@ -0,0 +1,68 @@
package main
import (
"fmt"
"os"
"sync"
"time"
)
// SafeWriter 线程安全的Writer封装
type SafeWriter struct {
writer *os.File
mu sync.Mutex // 互斥锁,保护Writer写入
}
// NewSafeWriter 创建SafeWriter实例
func NewSafeWriter(filename string) (*SafeWriter, error) {
file, err := os.OpenFile(filename,
os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
return &SafeWriter{writer: file}, nil
}
// Writef 线程安全的格式化写入
func (w *SafeWriter) Writef(format string, args ...interface{}) error {
w.mu.Lock() // 加锁,独占写入权
defer w.mu.Unlock() // 函数退出自动解锁
// 拼接日志前缀(时间)+ 格式化内容
logContent := fmt.Sprintf("[%s] %s\n",
time.Now().Format("2006-01-02 15:04:05"),
fmt.Sprintf(format, args...))
// 写入文件(用WriteString比Fprintf更高效)
_, err := w.writer.WriteString(logContent)
return err
}
// Close 关闭文件
func (w *SafeWriter) Close() error {
return w.writer.Close()
}
func main() {
writer, err := NewSafeWriter("concurrent.log")
if err != nil {
fmt.Printf("SafeWriter创建失败:%v\n", err)
return
}
defer writer.Close()
var wg sync.WaitGroup
// 10个goroutine并发写入(每个写10条)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(goroutineID int) {
defer wg.Done()
for j := 0; j < 10; j++ {
writer.Writef("goroutine%d:完成第%d条任务", goroutineID, j)
}
}(i)
}
wg.Wait()
fmt.Println("10个goroutine并发写入完成,内容无错乱")
}
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"fmt"
"sync"
"time"
)
var (
queue []int // 共享队列(生产者-消费者模型)
cmu sync.Mutex // 保护队列的互斥锁
cond = sync.NewCond(&cmu) // 基于mu创建条件变量
cwg sync.WaitGroup
)
// 生产者:向队列添加数据
func producer(id int) {
defer cwg.Done()
for i := 0; i < 3; i++ {
cmu.Lock()
data := id*10 + i
queue = append(queue, data)
fmt.Printf("生产者%d: 生产数据%d(队列长度%d\n", id, data, len(queue))
cmu.Unlock()
cond.Signal() // 唤醒一个等待的消费者(通知队列非空)
time.Sleep(500 * time.Millisecond)
}
}
// 消费者:等待队列非空后消费数据
func consumer(id int) {
defer cwg.Done()
for i := 0; i < 2; i++ { // 限定消费次数,避免无限等待
cmu.Lock()
// 循环等待:避免虚假唤醒(被唤醒时条件可能仍不满足)
for len(queue) == 0 {
cond.Wait() // 释放mu并阻塞,被唤醒时重新获取mu
}
if len(queue) > 0 { // 确保队列不为空
data := queue[0]
queue = queue[1:]
fmt.Printf("消费者%d: 消费数据%d(剩余长度%d\n", id, data, len(queue))
}
cmu.Unlock()
}
}
func main() {
cwg.Add(2) // 2个生产者
go producer(0)
go producer(1)
cwg.Add(3) // 3个消费者
go consumer(0)
go consumer(1)
go consumer(2)
cwg.Wait()
fmt.Println("所有生产者和消费者完成")
}
+52
View File
@@ -0,0 +1,52 @@
package main
import (
"context"
"fmt"
"time"
)
// 自定义上下文键
type key string
const RequestIDKey key = "request_id"
// 数据层:模拟数据库查询
func dataLayer(ctx context.Context) {
reqID, _ := ctx.Value(RequestIDKey).(string)
select {
case <-ctx.Done():
fmt.Printf("[数据层] 请求[%s]:超时取消 | 错误:%v\n", reqID, ctx.Err())
case <-time.After(1800 * time.Millisecond):
fmt.Printf("[数据层] 请求[%s]:数据查询成功\n", reqID)
}
}
// 服务层:业务逻辑处理
func serviceLayer(ctx context.Context) {
reqID, _ := ctx.Value(RequestIDKey).(string)
fmt.Printf("[服务层] 请求[%s]:开始业务处理\n", reqID)
dataLayer(ctx)
}
// API层:接口入口
func apiLayer(ctx context.Context) {
reqID, _ := ctx.Value(RequestIDKey).(string)
fmt.Printf("[API层] 请求[%s]:接收客户端请求\n", reqID)
serviceLayer(ctx)
}
func main() {
// 1. 上下文传递请求ID
ctx := context.WithValue(context.Background(), RequestIDKey, "REQ-2026-COM-001")
// 2. 设置超时时间:1.5秒
ctx, cancel := context.WithTimeout(ctx, 1500*time.Millisecond)
defer cancel()
// 3. 启动全链路调用
apiLayer(ctx)
time.Sleep(2 * time.Second)
fmt.Println("\n主协程:请求生命周期完整结束")
}
+46
View File
@@ -0,0 +1,46 @@
package main
import (
"context"
"fmt"
"time"
)
// 监听上下文信号的任务函数
func runTask(ctx context.Context, taskName string) {
for {
select {
case <-ctx.Done():
fmt.Printf("任务[%s]:收到退出信号,终止执行\n", taskName)
return
default:
fmt.Printf("任务[%s]:运行中...\n", taskName)
time.Sleep(300 * time.Millisecond)
}
}
}
func main() {
// 1. 创建父上下文
parentCtx, cancelParent := context.WithCancel(context.Background())
defer cancelParent()
// 2. 派生两个子上下文
childCtx1, _ := context.WithCancel(parentCtx)
childCtx2, _ := context.WithCancel(parentCtx)
// 3. 启动协程执行任务
go runTask(childCtx1, "子任务1")
go runTask(childCtx2, "子任务2")
// 4. 主协程运行2秒后取消父上下文
fmt.Println("主协程:2秒后取消所有子任务")
time.Sleep(2 * time.Second)
fmt.Println("\n主协程:取消父上下文")
cancelParent()
// 等待协程优雅退出
time.Sleep(1 * time.Second)
fmt.Println("主协程:所有任务已退出")
}
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"context"
"fmt"
"time"
)
// 模拟耗时业务任务
func businessTask(ctx context.Context, name string, duration time.Duration) {
fmt.Printf("任务[%s]:启动,预计耗时%v\n", name, duration)
select {
// 任务正常执行完成
case <-time.After(duration):
fmt.Printf("任务[%s]:执行完成\n", name)
// 上下文超时/取消触发
case <-ctx.Done():
fmt.Printf("任务[%s]:被终止,原因:%v\n", name, ctx.Err())
}
}
func main() {
// 创建全局超时上下文:2秒
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
// 任务11秒完成(正常)
go businessTask(ctx, "正常任务", 1*time.Second)
// 任务23秒完成(超时)
go businessTask(ctx, "超时任务", 3*time.Second)
// 等待所有任务执行完毕
time.Sleep(3 * time.Second)
fmt.Println("主协程:任务流程全部结束")
}
+44
View File
@@ -0,0 +1,44 @@
package main
import (
"context"
"fmt"
)
// 自定义键类型,防止键名冲突
type ctxKey string
// 定义上下文键常量
const (
TraceID ctxKey = "trace_id"
UserID ctxKey = "user_id"
)
// 业务处理函数:从上下文获取元数据
func handleRequest(ctx context.Context) {
// 安全类型断言获取值
traceID, ok := ctx.Value(TraceID).(string)
if !ok {
fmt.Println("未获取到追踪ID")
return
}
userID, ok := ctx.Value(UserID).(int)
if !ok {
fmt.Println("未获取到用户 ID")
return
}
fmt.Printf("请求处理中:TraceID=%sUserID=%d\n", traceID, userID)
}
func main() {
// 初始化根上下文
ctx := context.Background()
// 存入请求链路元数据
ctx = context.WithValue(ctx, TraceID, "20260324-CTX-001")
ctx = context.WithValue(ctx, UserID, 10000) // int
// 传递上下文到业务函数
handleRequest(ctx)
}
+98
View File
@@ -0,0 +1,98 @@
package main
import (
"errors"
"fmt"
)
// AppError 全局通用自定义错误
type AppError struct {
Code int // 业务错误码
Msg string // 错误描述
Module string // 所属模块
Status int // HTTP 状态码(可选扩展)
Err error // 底层原始错误(支持错误链)
}
// Error 实现标准 error 接口
func (e *AppError) Error() string {
return fmt.Sprintf("[%s] 错误码:%d | HTTP:%d | 描述:%s", e.Module, e.Code, e.Status, e.Msg)
}
// Unwrap 返回底层错误,支持 errors.Unwrap 和 errors.As 递归解包
func (e *AppError) Unwrap() error {
return e.Err
}
// 模拟数据库操作错误
func dbOperation(id string) error {
if id == "not_found" {
return fmt.Errorf("record [%s] not found: %w", id, errors.New("database empty"))
}
return nil
}
// 模拟业务逻辑
func businessDemo(name string) error {
if name == "invalid" {
return &AppError{
Code: 40010,
Msg: "参数非法",
Module: "user",
Status: 400,
}
}
if name == "db_error" {
dbErr := dbOperation("not_found")
return &AppError{
Code: 50001,
Msg: "数据库操作失败",
Module: "database",
Status: 500,
Err: dbErr, // 包装底层错误
}
}
return nil
}
// 统一错误处理
func parseError(err error) {
var appErr *AppError
// 断言自定义错误
if errors.As(err, &appErr) {
fmt.Printf("捕获业务错误:%+v\n", appErr)
// 如果有底层错误,继续解包
if appErr.Unwrap() != nil {
fmt.Printf("底层错误:%v\n", appErr.Unwrap())
// 使用 errors.Is 检测底层错误
if errors.Is(appErr.Unwrap(), errors.New("database empty")) {
fmt.Println("判定:底层是数据库空错误")
}
}
return
}
// 处理通用错误
if err != nil {
fmt.Printf("捕获系统错误:%v\n", err)
}
}
func main() {
fmt.Println("===== 自定义错误类型 =====")
err := businessDemo("invalid")
parseError(err)
fmt.Println("\n===== 带错误链的自定义错误 =====")
err2 := businessDemo("db_error")
parseError(err2)
fmt.Println("\n===== 使用 errors.As 深度提取 =====")
var appErr *AppError
if errors.As(err2, &appErr) {
fmt.Printf("提取到 AppError - 模块:%s, 错误码:%d\n", appErr.Module, appErr.Code)
}
}
+1
View File
@@ -0,0 +1 @@
1122
+13
View File
@@ -0,0 +1,13 @@
package main
import (
_ "embed"
"fmt"
)
//go:embed version.txt
var version string
func main() {
fmt.Println("Version:", version)
}
+1
View File
@@ -0,0 +1 @@
1.0.0
+29
View File
@@ -0,0 +1,29 @@
package main
import "fmt"
func main() {
// 定义格式字符串常量(避免硬编码导致的数量/格式错误)
const userFormat = "用户信息:ID=%d,姓名=%s,年龄=%d \n"
// 1. 处理参数类型不匹配错误
_, err := fmt.Printf(userFormat, "invalid_id", "sanmiao", 20) // ID应为int,却传string
if err != nil {
fmt.Printf("格式化错误(类型不匹配):%v\n", err)
}
// 输出:用户信息:ID=%!d(string=invalid_id),姓名=sanmiao,年龄=20
// 2. 处理参数数量不匹配错误
_, err = fmt.Printf(userFormat, 1001, "sanmiao") // 缺少“年龄”参数
if err != nil {
fmt.Printf("格式化错误(数量不匹配):%v\n", err)
}
// 输出:用户信息:ID=1001,姓名=sanmiao,年龄=%!d(MISSING)
// 3. 正确用法
_, err = fmt.Printf(userFormat, 1001, "sanmiao", 20)
if err == nil {
fmt.Println("\n格式化成功!")
}
// 输出:用户信息:ID=1001,姓名=sanmiao,年龄=20
}
+97
View File
@@ -0,0 +1,97 @@
package main
//
//import (
// "errors"
// "fmt"
// "os"
//)
//
//// 自定义全局错误
//type BizError struct {
// Code int
// Msg string
// Module string
// Err error // 添加底层错误
//}
//
//func (e *BizError) Error() string {
// return fmt.Sprintf("[%s] %d: %s", e.Module, e.Code, e.Msg)
//}
//
//// Unwrap 返回底层错误,支持 errors.Is 和 errors.As 递归解包
//func (e *BizError) Unwrap() error {
// return e.Err
//}
//
//// 哨兵错误
//var ErrFileNotFound = errors.New("file not found")
//
//// 底层方法:包装系统错误
//func open(name string) error {
// _, err := os.Open(name)
// if err != nil {
// return fmt.Errorf("open exec: %w", ErrFileNotFound)
// }
// return nil
//}
//
//// 业务方法:包装底层错误 + 自定义错误
//func handleFile(name string) error {
// if err := open(name); err != nil {
// // 触发自定义业务错误
// return &BizError{
// Code: 50001,
// Msg: "文件处理异常",
// Module: "file",
// Err: err, // 包装底层错误
// }
// }
// return nil
//}
//
//// 统一错误解析
//func resolveError(err error) {
// if err == nil {
// return
// }
// fmt.Printf("完整错误:%v\n", err)
//
// // 1. 断言自定义错误
// var biz *BizError
// if errors.As(err, &biz) {
// fmt.Printf("自定义错误:%v\n", biz)
// // 2. 如果有底层错误,递归检查哨兵错误
// if biz.Unwrap() != nil {
// fmt.Printf("底层错误:%v\n", biz.Unwrap())
//
// // 3. 检查哨兵错误
// if errors.Is(biz.Unwrap(), ErrFileNotFound) {
// fmt.Println("✓ 哨兵错误:文件不存在")
// }
// }
// } else {
// // 4. 直接检查哨兵错误(兼容简单错误链)
// if errors.Is(err, ErrFileNotFound) {
// fmt.Println("✓ 哨兵错误:文件不存在")
// }
// }
//
// // 5. 服务降级
// fmt.Println("执行降级:返回默认文件内容")
//}
//
//func main() {
// fmt.Println("===== Go 错误处理综合实战 =====")
// err := handleFile("demo.txt")
// resolveError(err)
// fmt.Println("\n===== 测试正常情况 =====")
// // 创建一个存在的文件进行测试
// tmpFile := "temp_test.txt"
// os.WriteFile(tmpFile, []byte("test"), 0644)
// err2 := handleFile(tmpFile)
// if err2 == nil {
// fmt.Println("文件处理成功")
// }
// os.Remove(tmpFile)
//}
+154
View File
@@ -0,0 +1,154 @@
package main
import (
"context"
"errors"
"fmt"
"strings"
"testing"
)
// ------------------------------
// 错误类型定义(核心优化)
// ------------------------------
// FileError 自定义文件服务错误结构体
type FileError struct {
Code int // 错误码
Module string // 所属模块
Message string // 错误信息
Err error // 原始错误(支持错误包装/解包)
}
// Error 实现 error 接口
func (e *FileError) Error() string {
if e.Err != nil {
return fmt.Sprintf("[%s:%d] %s: %v", e.Module, e.Code, e.Message, e.Err)
}
return fmt.Sprintf("[%s:%d] %s", e.Module, e.Code, e.Message)
}
// Unwrap 实现 errors.Unwrap 支持错误链解包
func (e *FileError) Unwrap() error {
return e.Err
}
// 预定义错误(使用 sentinel error 规范)
var ErrFileNotFound = errors.New("file not found")
// ------------------------------
// 业务服务实现
// ------------------------------
// FileService 基础文件服务
func FileService(ctx context.Context, filename string) error {
// 模块名称常量
const module = "FileService"
// 1. 空文件名校验(400
if filename == "" {
return &FileError{
Code: 400,
Module: module,
Message: "filename cannot be empty",
}
}
// 2. 文件不存在模拟(404
return &FileError{
Code: 404,
Module: module,
Message: "file does not exist",
Err: ErrFileNotFound, // 包装原始哨兵错误
}
}
// AdvancedFileService 高级文件服务(包装基础服务)
func AdvancedFileService(ctx context.Context, filename string) error {
// 调用底层服务并包装错误信息
if err := FileService(ctx, filename); err != nil {
return fmt.Errorf("advanced file service failed: %s %w", filename, err)
}
return nil
}
// ------------------------------go vet
// 测试用例
// ------------------------------
func TestFileService(t *testing.T) {
ctx := context.Background()
// 子测试用例(清晰分组,便于定位失败)
t.Run("file not found returns 404 error", func(t *testing.T) {
err := FileService(ctx, "test.txt")
// 断言哨兵错误
if !errors.Is(err, ErrFileNotFound) {
t.Fatalf("期望错误: %v, 实际错误: %v", ErrFileNotFound, err)
}
// 断言自定义错误类型与字段
var fErr *FileError
if !errors.As(err, &fErr) {
t.Fatal("期望返回 *FileError 类型")
}
if fErr.Code != 404 {
t.Errorf("错误码期望 404, 实际 %d", fErr.Code)
}
if fErr.Module != "FileService" {
t.Errorf("模块期望 FileService, 实际 %s", fErr.Module)
}
})
t.Run("empty filename returns 400 error", func(t *testing.T) {
err := FileService(ctx, "")
if err == nil {
t.Fatal("空文件名必须返回错误")
}
var fErr *FileError
if !errors.As(err, &fErr) {
t.Fatal("期望返回 *FileError 类型")
}
if fErr.Code != 400 {
t.Errorf("错误码期望 400, 实际 %d", fErr.Code)
}
})
}
func TestErrorWrapping(t *testing.T) {
original := errors.New("original error")
wrapped := fmt.Errorf("wrapped: %w", original)
// 测试 errors.Is 错误链匹配
if !errors.Is(wrapped, original) {
t.Error("errors.Is 应当匹配包装后的错误")
}
// 测试 errors.Unwrap 解包
unwrapped := errors.Unwrap(wrapped)
if unwrapped != original {
t.Errorf("解包后应当返回原始错误, 实际: %v", unwrapped)
}
}
func TestAdvancedFileService(t *testing.T) {
ctx := context.Background()
err := AdvancedFileService(ctx, "nonexistent.txt")
if err == nil {
t.Fatal("必须返回错误")
}
// 错误信息包含文件名
if !strings.Contains(err.Error(), "nonexistent.txt") {
t.Errorf("错误信息应当包含文件名, 实际: %v", err)
}
// 错误链中能找到自定义 FileError
var fErr *FileError
if !errors.As(err, &fErr) {
t.Error("错误链中应当包含 *FileError")
}
}
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"errors"
"fmt"
)
// 哨兵错误
var (
ErrCacheOffline = errors.New("cache offline")
ErrRequestTimeout = errors.New("request timeout")
)
func main() {
fmt.Println("===== 错误处理模式 =====")
// 1. 快速失败
if err := errors.New("config load failed"); err != nil {
// 测试后面的把这一行 log.Fatalln 注释掉
// log.Fatalln("快速失败:服务启动终止 ->", err)
}
// 2. 服务降级
cacheErr := fmt.Errorf("get data failed: %w", ErrCacheOffline)
if errors.Is(cacheErr, ErrCacheOffline) {
fmt.Println("降级策略:缓存故障,使用数据库默认数据")
}
// 3. 容错忽略
fmt.Println("容错处理:埋点上报失败,忽略不影响主流程")
}
+76
View File
@@ -0,0 +1,76 @@
package main
//
//import (
// "errors"
// "fmt"
// "os"
//)
//
//// 自定义错误类型:文件不存在错误
//type FileNotExistError struct {
// Filename string
//}
//
//func (e *FileNotExistError) Error() string {
// return fmt.Sprintf("file [%s] does not exist", e.Filename)
//}
//
//// 多层函数调用:模拟文件操作 + 错误包装
//func readFile(name string) error {
// if err := openFile(name); err != nil {
// // 上层包装:添加上下文
// return fmt.Errorf("readFile failed: %w", err)
// }
// return nil
//}
//
//func openFile(name string) error {
// // 底层错误:系统原生错误
// _, err := os.Open(name)
// if err != nil {
// // 底层包装:绑定文件名上下文
// return fmt.Errorf("open file [%s] failed: %w", name, err)
// }
// return nil
//}
//
//func main() {
// fmt.Println("===== 错误包装与链追踪 =====")
// err := readFile("not_exist.txt")
//
// // 输出完整错误链
// fmt.Println("完整错误:", err)
// // 单次解包
// fmt.Println("解包一层:", errors.Unwrap(err))
// // 递归检测系统错误
// if errors.Is(err, os.ErrNotExist) {
// fmt.Println("判定结果:文件不存在")
// }
//
// fmt.Println("\n===== 使用 errors.As 提取特定错误类型 =====")
//
// // 演示 errors.As:提取路径错误类型
// var pathErr *os.PathError
// if errors.As(err, &pathErr) {
// fmt.Printf("提取到 PathError: 操作=%s, 路径=%s\n", pathErr.Op, pathErr.Path)
// }
//
// // 演示 errors.As:提取系统错误
// var sysErr error
// if errors.As(err, &sysErr) {
// if errors.Is(sysErr, os.ErrNotExist) {
// fmt.Println("通过 errors.As+Is 确认:底层是 ErrNotExist")
// }
// }
//
// // 自定义错误类型示例
// fmt.Println("\n===== 自定义错误类型示例 =====")
// customErr := &FileNotExistError{Filename: "test.txt"}
// wrappedCustom := fmt.Errorf("config load failed: %w", customErr)
//
// var fileErr *FileNotExistError
// if errors.As(wrappedCustom, &fileErr) {
// fmt.Printf("提取到自定义错误类型:文件名=%s\n", fileErr.Filename)
// }
//}
+32
View File
@@ -0,0 +1,32 @@
package main
import "fmt"
type Person4 struct {
Name string
Age int
}
// closureEscape 返回闭包,捕获的变量逃逸
func closureEscape() func() *Person4 {
p := &Person4{Name: "Closure Person", Age: 30} // p 逃逸至堆
return func() *Person4 {
return p // 闭包引用p,延长其生命周期
}
}
// goroutineClosure 协程中使用闭包,捕获变量逃逸
func goroutineClosure() {
x := 100 // x 逃逸至堆
go func() {
fmt.Printf("协程闭包捕获:%d\n", x)
}()
}
func main() {
closureFunc := closureEscape()
p := closureFunc()
fmt.Printf("闭包捕获变量:%+v\n", *p)
goroutineClosure()
}
+51
View File
@@ -0,0 +1,51 @@
package main
import "fmt"
// Animal 接口定义
type Animal interface {
Speak() string
}
// Dog 实现Animal接口
type Dog struct{}
func (d Dog) Speak() string {
return "汪汪汪"
}
// Cat 实现Animal接口
type Cat struct{}
func (c Cat) Speak() string {
return "喵喵喵"
}
// interfaceEscape 变量赋值给接口,触发逃逸
func interfaceEscape(animalType string) Animal {
var a Animal
if animalType == "dog" {
d := Dog{} // d 逃逸至堆
a = d
} else {
c := Cat{} // c 逃逸至堆
a = c
}
return a
}
// interfacePointer 指针赋值给接口,触发逃逸
func interfacePointer() interface{} {
p := &Dog{} // p 逃逸至堆
return p
}
func main() {
animal := interfaceEscape("dog")
fmt.Printf("接口动态派发:%s\n", animal.Speak())
iface := interfacePointer()
if dog, ok := iface.(*Dog); ok {
fmt.Printf("接口指针逃逸:%s\n", dog.Speak())
}
}
+29
View File
@@ -0,0 +1,29 @@
package main
import "fmt"
// largeArrayEscape 大数组指针返回,触发逃逸
func largeArrayEscape() *[10000]int {
arr := new([10000]int) // 8MB(int占8字节),超过栈阈值,逃逸至堆
for i := 0; i < 10000; i++ {
arr[i] = i
}
return arr
}
// smallArrayNoEscape 小数组,不逃逸
func smallArrayNoEscape() [10]int {
var arr [10]int
for i := 0; i < 10; i++ {
arr[i] = i
}
return arr // 值拷贝,不逃逸
}
func main() {
largeArr := largeArrayEscape()
fmt.Printf("大数组逃逸:长度=%d\n", len(largeArr))
smallArr := smallArrayNoEscape()
fmt.Printf("小数组不逃逸:%v\n", smallArr)
}
+29
View File
@@ -0,0 +1,29 @@
package main
import "fmt"
type Person8 struct {
Name string
Age int
}
// noEscape 返回值类型,不逃逸
func noEscape() Person8 {
p := Person8{Name: "No Escape", Age: 25}
return p // 值拷贝,生命周期局限于函数内
}
// localVar 局部变量,未被外部引用,不逃逸
func localVar() {
x := 100
y := "hello"
p := Person8{Name: "Local", Age: 30}
fmt.Printf("局部变量不逃逸:x=%d, y=%s, p=%+v\n", x, y, p)
}
func main() {
p := noEscape()
fmt.Printf("返回值不逃逸:%+v\n", p)
localVar()
}
+85
View File
@@ -0,0 +1,85 @@
package main
import (
"fmt"
"sync"
)
type Person struct {
Name string
Age int
}
// 优化1:避免不必要的指针传递(小结构体)
// 优化前:指针传递,可能触发逃逸
func processPersonOld(p *Person) string {
return fmt.Sprintf("%s is %d years old", p.Name, p.Age)
}
// 优化后:值传递,不逃逸
func processPersonNew(p Person) string {
return fmt.Sprintf("%s is %d years old", p.Name, p.Age)
}
// 优化2:提前确定切片容量,避免动态扩容逃逸
// 优化前:动态扩容,底层数组逃逸
func sliceEscape() []int {
s := make([]int, 0)
for i := 0; i < 100; i++ {
s = append(s, i)
}
return s
}
// 优化后:指定容量,不逃逸
func sliceNoEscape() []int {
s := make([]int, 0, 100) // 编译期确定容量
for i := 0; i < 100; i++ {
s = append(s, i)
}
return s
}
// 优化3:使用对象池复用对象,减少堆分配
var personPool = sync.Pool{
New: func() interface{} {
return &Person{} // 初始化对象,仅分配一次(或按需分配)
},
}
// 优化前:频繁创建对象,多次堆分配
func createPersonOld(name string, age int) *Person {
return &Person{Name: name, Age: age} // 每次调用都逃逸,触发堆分配
}
// 优化后:复用对象池中的对象,减少堆分配
func createPersonNew(name string, age int) *Person {
p := personPool.Get().(*Person)
p.Name = name
p.Age = age
return p
}
// 释放对象到池
func releasePerson(p *Person) {
// 重置对象状态(避免残留数据)
p.Name = ""
p.Age = 0
personPool.Put(p)
}
func main() {
// 优化1测试
p := Person{Name: "Alice", Age: 25}
fmt.Println("优化1-值传递:", processPersonNew(p))
// 优化2测试
s1 := sliceEscape()
s2 := sliceNoEscape()
fmt.Printf("优化2-切片:逃逸len=%d, 不逃逸len=%d\n", len(s1), len(s2))
// 优化3测试
p1 := createPersonNew("Bob", 30)
fmt.Println("优化3-对象池:", *p1)
releasePerson(p1)
}
+31
View File
@@ -0,0 +1,31 @@
package main
import "fmt"
type Person7 struct {
Name string
Age int
}
type Manager struct {
Person7 *Person7 // 关联Person指针
}
// GetPerson 返回关联的Person指针,触发逃逸
func (m *Manager) GetPerson() *Person7 {
return m.Person7 // Person指针逃逸
}
// createManager 返回Manager指针,触发逃逸
func createManager() *Manager {
m := &Manager{
Person7: &Person7{Name: "Manager Person", Age: 40}, // Person逃逸
}
return m // Manager指针逃逸
}
func main() {
manager := createManager()
person := manager.GetPerson()
fmt.Printf("方法接收者逃逸:%+v\n", *person)
}
+45
View File
@@ -0,0 +1,45 @@
package main
import "fmt"
// 全局变量,存储Person指针
var globalPerson *Person2
// 全局切片,存储Person指针
var globalPersonSlice []*Person2
type Person2 struct {
Name string
Age int
}
// storePerson 接收指针参数并返回,触发逃逸
func storePerson(p *Person2) *Person2 {
return p // 指针被返回,触发逃逸
}
// addToGlobal 将指针存入全局变量,触发逃逸
func addToGlobal() {
p := &Person2{Name: "Bob", Age: 30}
globalPerson = p // 存入全局变量,p逃逸
}
// addToGlobalSlice 将指针存入全局切片,触发逃逸
func addToGlobalSlice() {
for i := 0; i < 3; i++ {
p := &Person2{Name: fmt.Sprintf("Person%d", i), Age: 20 + i}
globalPersonSlice = append(globalPersonSlice, p) // p逃逸至切片
}
}
func main() {
p := &Person2{Name: "Charlie", Age: 28}
storedP := storePerson(p)
fmt.Printf("引用传递:%+v\n", *storedP)
addToGlobal()
fmt.Printf("全局变量存储:%+v\n", *globalPerson)
addToGlobalSlice()
fmt.Printf("全局切片存储:%d个Person\n", len(globalPersonSlice))
}
+20
View File
@@ -0,0 +1,20 @@
package main
import "fmt"
// Person 测试结构体
type Person struct {
Name string
Age int
}
// newPerson 返回局部变量指针,触发逃逸
func newPerson(name string, age int) *Person {
p := &Person{Name: name, Age: age} // p 逃逸至堆
return p
}
func main() {
p := newPerson("Alice", 25)
fmt.Printf("局部变量指针返回:%+v\n", *p)
}
+45
View File
@@ -0,0 +1,45 @@
package main
import "fmt"
type Person3 struct {
Name string
Age int
}
// sliceEscape 切片元素为指针,且切片被返回,元素逃逸
func sliceEscape() []*Person3 {
var people []*Person3
for i := 0; i < 3; i++ {
person := &Person3{Name: fmt.Sprintf("Person3%d", i), Age: 20 + i}
people = append(people, person) // person 逃逸
}
return people
}
// dynamicSlice 切片动态扩容,底层数组逃逸
func dynamicSlice() []int {
s := make([]int, 0) // 编译期无法确定最终容量
for i := 0; i < 100; i++ {
s = append(s, i) // 扩容时底层数组逃逸
}
return s
}
// mapEscape 映射值为指针,值逃逸
func mapEscape() map[string]*Person3 {
m := make(map[string]*Person3)
m["alice"] = &Person3{Name: "Alice", Age: 25} // 指针值逃逸
return m
}
func main() {
people := sliceEscape()
fmt.Printf("切片元素逃逸:%d个Person\n", len(people))
s := dynamicSlice()
fmt.Printf("切片扩容逃逸:len=%d, cap=%d\n", len(s), cap(s))
m := mapEscape()
fmt.Printf("映射值逃逸:%+v\n", *m["alice"])
}
+2
View File
@@ -0,0 +1,2 @@
[2026-05-06 14:07:08] 服务启动成功
[2026-05-06 14:07:27] 服务启动成功
+1
View File
@@ -0,0 +1 @@
{"env":"production","version":"1.0.0"}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
Go文件操作最佳实践
+1
View File
@@ -0,0 +1 @@
测试embed文件
+155
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
test文件内容测试111111111111
+24
View File
@@ -0,0 +1,24 @@
package main
import (
"os"
)
// 标准资源释放:打开文件后立即defer关闭,检查关闭错误
func main() {
// 打开文件
file, err := os.Open("file/test.txt")
// 核心:必须处理打开错误
if err != nil {
panic("文件打开失败:" + err.Error())
}
// 核心:defer延迟关闭,函数退出前自动释放句柄
defer func() {
// 关闭文件时检查错误,释放资源同时捕获异常
if closeErr := file.Close(); closeErr != nil {
panic("文件关闭失败:" + closeErr.Error())
}
}()
// 执行业务读写逻辑
}
+43
View File
@@ -0,0 +1,43 @@
package main
import (
"errors"
"fmt"
"io"
"os"
)
func fileOperation() error {
// 1. 打开文件错误处理
file, err := os.OpenFile("file/data.log", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
// 包装错误,添加上下文
return fmt.Errorf("打开文件失败: %w", err)
}
defer func() {
if closeErr := file.Close(); closeErr != nil {
fmt.Printf("警告:文件关闭异常: %v\n", closeErr)
}
}()
// 2. 写入数据错误处理
content := []byte("Go文件操作最佳实践")
n, err := io.WriteString(file, string(content))
if err != nil {
return fmt.Errorf("文件写入失败: %w", err)
}
if n != len(content) {
return errors.New("文件写入不完整")
}
return nil
}
func main() {
if err := fileOperation(); err != nil {
fmt.Printf("文件操作执行失败: %v\n", err)
return
}
fmt.Println("文件操作成功")
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"fmt"
"os"
)
// 小文件一次性读写:代码简洁,无资源泄漏风险
func smallFileRW() {
path := "file/config.json"
content := []byte(`{"env":"production","version":"1.0.0"}`)
// 一次性写入:自动创建文件、覆盖内容、关闭文件
err := os.WriteFile(path, content, 0644)
if err != nil {
fmt.Printf("写入失败: %v\n", err)
return
}
// 一次性读取:自动打开、读取、关闭文件
data, err := os.ReadFile(path)
if err != nil {
fmt.Printf("读取失败: %v\n", err)
return
}
fmt.Printf("文件内容: %s\n", string(data))
}
func main() {
smallFileRW()
}
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"bufio"
"fmt"
"io"
"os"
)
// 大文件缓冲读写:逐行处理,内存占用恒定
func bigFileRW() {
// 打开源文件
srcFile, err := os.Open("file/large_file.txt")
if err != nil {
fmt.Printf("打开源文件失败: %v\n", err)
return
}
defer srcFile.Close()
// 创建目标文件
dstFile, err := os.Create("file/copy_large_file.txt")
if err != nil {
fmt.Printf("创建目标文件失败: %v\n", err)
return
}
defer dstFile.Close()
// 创建缓冲读写器
reader := bufio.NewReader(srcFile)
writer := bufio.NewWriter(dstFile)
defer func() {
// 刷新缓冲区并检查错误
if err := writer.Flush(); err != nil {
fmt.Printf("缓冲区刷新失败: %v\n", err)
}
}()
// 逐行读取写入
for {
line, err := reader.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("读取失败: %v\n", err)
return
}
_, err = writer.WriteString(line)
if err != nil {
fmt.Printf("写入失败: %v\n", err)
return
}
}
fmt.Println("大文件拷贝完成")
}
func main() {
bigFileRW()
}
+36
View File
@@ -0,0 +1,36 @@
package main
import (
"fmt"
"os"
"time"
)
// 文件追加写入:日志场景最佳实践
func appendFile() {
path := "file/app.log"
// 打开模式:O_CREATE(不存在则创建)|O_APPEND(追加)|O_WRONLY(只写)
file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("打开日志文件失败: %v\n", err)
return
}
defer func() {
if err := file.Close(); err != nil {
fmt.Printf("关闭文件失败: %v\n", err)
}
}()
// 写入日志
log := fmt.Sprintf("[%s] 服务启动成功\n", time.Now().Format("2006-01-02 15:04:05"))
_, err = file.WriteString(log)
if err != nil {
fmt.Printf("写入日志失败: %v\n", err)
return
}
fmt.Println("日志追加成功")
}
func main() {
appendFile()
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"fmt"
"os"
)
func getFileInfo() {
path := "file/test.txt"
// 获取文件信息
info, err := os.Stat(path)
if err != nil {
// 判断文件是否不存在
if os.IsNotExist(err) {
fmt.Println("文件不存在")
return
}
fmt.Printf("获取文件信息失败: %v\n", err)
return
}
// 输出元数据
fmt.Printf("文件名: %s\n", info.Name())
fmt.Printf("文件大小: %d 字节\n", info.Size())
fmt.Printf("文件权限: %s\n", info.Mode().String())
fmt.Printf("修改时间: %s\n", info.ModTime().Format("2006-01-02"))
fmt.Printf("是否为目录: %t\n", info.IsDir())
}
func main() {
getFileInfo()
}
+23
View File
@@ -0,0 +1,23 @@
package main
import (
"embed"
"fmt"
)
//go:embed file/embed.txt
var embedFile embed.FS
func embedFileDemo() {
// 读取编译嵌入的文件,无磁盘IO操作
data, err := embedFile.ReadFile("file/embed.txt")
if err != nil {
fmt.Printf("读取嵌入文件失败: %v\n", err)
return
}
fmt.Printf("嵌入文件内容: %s\n", string(data))
}
func main() {
embedFileDemo()
}
View File
+24
View File
@@ -0,0 +1,24 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 方式1:变量绑定
var name string
flag.StringVar(&name, "name", "guest", "用户名")
// 方式2:指针获取
age := flag.Int("age", 18, "用户年龄")
enable := flag.Bool("enable", false, "是否启用功能")
// 解析命令行参数
flag.Parse()
// 输出结果
fmt.Printf("用户名:%s\n", name)
fmt.Printf("年龄:%d\n", *age)
fmt.Printf("功能启用:%t\n", *enable)
}
View File
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"flag"
"fmt"
"os"
"strconv"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
host := flag.String("host", "localhost", "服务绑定主机")
flag.Parse()
// 环境变量仅覆盖未手动传参的配置
if !flag.IsSet("port") {
if envPort := os.Getenv("SERVICE_PORT"); envPort != "" {
if p, err := strconv.Atoi(envPort); err == nil {
*port = p
}
}
}
if !flag.IsSet("host") {
if envHost := os.Getenv("SERVICE_HOST"); envHost != "" {
*host = envHost
}
}
fmt.Printf("最终生效配置:主机=%s,端口=%d\n", *host, *port)
}
+41
View File
@@ -0,0 +1,41 @@
package main
import (
"flag"
"fmt"
"os"
)
func main() {
port := flag.Int("port", 8080, "服务监听端口")
config := flag.String("config", "./config.yaml", "配置文件路径")
// 重写全局帮助信息
flag.Usage = func() {
_, err := fmt.Fprintf(flag.CommandLine.Output(), "=== 服务启动工具 V1.0 ===\n\n")
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), "用法:%s [可选参数]\n\n", os.Args[0])
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), "参数说明:\n")
if err != nil {
return
}
flag.PrintDefaults()
_, err = fmt.Fprintf(flag.CommandLine.Output(), "\n使用示例:\n")
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), " %s -port=8080 -config=app.yaml\n", os.Args[0])
if err != nil {
return
}
}
flag.Parse()
fmt.Printf("服务启动成功,端口:%d,配置文件:%s\n", *port, *config)
}
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"flag"
"fmt"
"strings"
)
// PortRange 自定义端口范围类型,支持 min-max 格式
type PortRange struct {
Min int
Max int
}
// Set 实现Value接口,完成参数解析和合法性校验
func (p *PortRange) Set(s string) error {
parts := strings.Split(s, "-")
if len(parts) != 2 {
return fmt.Errorf("格式错误,端口范围格式必须为 minV-max")
}
var minV, maxV int
_, err1 := fmt.Sscanf(parts[0], "%d", &minV)
_, err2 := fmt.Sscanf(parts[1], "%d", &maxV)
if err1 != nil || err2 != nil {
return fmt.Errorf("端口必须为整数")
}
if minV < 1 || minV > 65535 || maxV < 1 || maxV > 65535 || minV > maxV {
return fmt.Errorf("端口范围必须在1-65535之间,且min <= max")
}
p.Min = minV
p.Max = maxV
return nil
}
// String 实现Value接口,定义默认值与字符串展示
func (p *PortRange) String() string {
if p.Min == 0 && p.Max == 0 {
return "1-65535"
}
return fmt.Sprintf("%d-%d", p.Min, p.Max)
}
// Get 实现Getter接口,返回原始类型,支持类型断言
func (p *PortRange) Get() any {
return *p
}
func main() {
var portRange PortRange
flag.Var(&portRange, "port-range", "端口范围,格式:min-max")
flag.Parse()
fmt.Printf("有效端口范围:[%d, %d]\n", portRange.Min, portRange.Max)
fmt.Printf("类型安全取值:%#v\n", portRange.Get().(PortRange))
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"flag"
"fmt"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
flag.Parse()
fmt.Println("动态修改前端口:", *port)
// 动态覆盖参数值
if err := flag.Set("port", "9090"); err != nil {
fmt.Println("参数设置失败:", err)
}
fmt.Println("动态修改后端口:", *port)
// 精准查询参数元信息
if f := flag.Lookup("port"); f != nil {
fmt.Printf("参数详情:名称=%s, 当前值=%s, 默认值=%s, 用途=%s\n",
f.Name, f.Value.String(), f.DefValue, f.Usage)
}
}
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"flag"
"fmt"
"strings"
)
// Environment 运行环境枚举类型
type Environment string
const (
EnvDev Environment = "dev"
EnvTest Environment = "test"
EnvProd Environment = "prod"
)
// 合法环境白名单
var validEnvs = map[Environment]bool{
EnvDev: true,
EnvTest: true,
EnvProd: true,
}
func (e *Environment) Set(s string) error {
env := Environment(strings.ToLower(s))
if !validEnvs[env] {
return fmt.Errorf("无效运行环境,仅支持 dev/test/prod")
}
*e = env
return nil
}
func (e *Environment) String() string {
if *e == "" {
return string(EnvDev)
}
return string(*e)
}
func (e *Environment) Get() any {
return *e
}
func main() {
var env Environment = EnvDev // 默认值为 dev
flag.Var(&env, "env", "运行环境:dev/test/prod")
flag.Parse()
fmt.Printf("当前运行环境:%s\n", env)
}
+20
View File
@@ -0,0 +1,20 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 子命令标准模式:手动捕获错误,不自动退出
fs := flag.NewFlagSet("demo", flag.ContinueOnError)
num := fs.Int("num", 0, "数字参数")
// 传入非法参数
err := fs.Parse([]string{"-num=abc"})
if err != nil {
fmt.Printf("参数解析失败:%v\n", err)
return
}
fmt.Println("参数值:", *num)
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 普通函数参数,传参即触发回调
flag.Func("msg", "自定义消息参数", func(s string) error {
fmt.Println("接收参数消息:", s)
return nil
})
// 布尔函数参数,无值传参触发
flag.BoolFunc("debug", "开启调试模式", func(s string) error {
fmt.Println("调试模式状态:", s)
return nil
})
flag.Parse()
}
+50
View File
@@ -0,0 +1,50 @@
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
)
// FilePath 带合法性校验的文件路径类型
type FilePath string
func (f *FilePath) Set(s string) error {
// 解析绝对路径
absPath, err := filepath.Abs(s)
if err != nil {
return fmt.Errorf("路径解析失败:%w", err)
}
// 校验文件存在且为普通文件
info, err := os.Stat(absPath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("配置文件不存在:%s", absPath)
}
return fmt.Errorf("文件访问异常:%w", err)
}
if info.IsDir() {
return fmt.Errorf("路径为目录,需传入有效文件路径:%s", absPath)
}
*f = FilePath(absPath)
return nil
}
func (f *FilePath) String() string {
return string(*f)
}
func (f *FilePath) Get() any {
return string(*f)
}
func main() {
var configFile FilePath
flag.Var(&configFile, "config", "必填配置文件路径")
flag.Parse()
fmt.Printf("加载配置文件:%s\n", configFile)
}
+19
View File
@@ -0,0 +1,19 @@
package main
import (
"flag"
"fmt"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
flag.Parse()
// 获取无标记位置参数
args := flag.Args()
if len(args) == 0 {
fmt.Println("请传入配置文件路径")
return
}
fmt.Printf("端口:%d,配置文件:%s\n", *port, args[0])
}
+25
View File
@@ -0,0 +1,25 @@
package main
import (
"flag"
"fmt"
"strings"
)
type StringSlice2 []string
func (s *StringSlice2) Set(val string) error {
*s = append(*s, val)
return nil
}
func (s *StringSlice2) String() string {
return strings.Join(*s, ",")
}
func main() {
var files StringSlice2
flag.Var(&files, "file", "指定多个配置文件,可重复传参")
flag.Parse()
fmt.Printf("文件列表:%#v\n", files)
}
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"flag"
"fmt"
"strings"
)
// StringSlice 支持重复传参的字符串切片类型
type StringSlice []string
// Set 实现参数追加逻辑,覆盖原生覆盖问题
func (s *StringSlice) Set(value string) error {
*s = append(*s, value)
return nil
}
// String 实现字符串展示与零值返回
func (s *StringSlice) String() string {
if len(*s) == 0 {
return "[]"
}
return strings.Join(*s, ",")
}
// Get 实现Getter接口,返回原始切片类型
func (s *StringSlice) Get() any {
return []string(*s)
}
func main() {
var files StringSlice
var tags StringSlice
flag.Var(&files, "file", "指定配置文件,可重复传参")
flag.Var(&tags, "tag", "自定义业务标签,可重复传参")
flag.Parse()
fmt.Printf("文件列表:%v (原始类型:%T)\n", files.Get(), files.Get())
fmt.Printf("标签列表:%v (原始类型:%T)\n", tags.Get(), tags.Get())
}
+38
View File
@@ -0,0 +1,38 @@
package main
import (
"flag"
"fmt"
"os"
)
func main() {
// 初始化子命令FlagSet
startCmd := flag.NewFlagSet("start", flag.ContinueOnError)
stopCmd := flag.NewFlagSet("stop", flag.ContinueOnError)
// 子命令私有参数
var port int
var config string
startCmd.IntVar(&port, "port", 8080, "服务监听端口")
stopCmd.StringVar(&config, "config", "./config.yaml", "服务配置文件")
// 校验子命令是否传入
if len(os.Args) < 2 {
fmt.Println("可用子命令:start / stop")
os.Exit(1)
}
// 路由分发
switch os.Args[1] {
case "start":
_ = startCmd.Parse(os.Args[2:])
fmt.Printf("启动服务成功,端口:%d\n", port)
case "stop":
_ = stopCmd.Parse(os.Args[2:])
fmt.Printf("停止服务,配置文件:%s\n", config)
default:
fmt.Printf("未知子命令:%s\n", os.Args[1])
os.Exit(1)
}
}
+128
View File
@@ -0,0 +1,128 @@
package main
import (
"flag"
"fmt"
"os"
)
// GlobalOptions 全局公共参数,所有子命令共享
type GlobalOptions struct {
Verbose bool // 详细日志模式
Config string // 全局配置文件
}
// SubCommand 通用子命令抽象结构体
type SubCommand struct {
Name string
Description string
Flags *flag.FlagSet
Run func([]string, GlobalOptions) error
}
// 提前声明变量,避免初始化循环引用
var commands map[string]*SubCommand
// init 初始化子命令,将 FlagSet 的绑定与执行逻辑分离
func init() {
// --- 初始化 build 命令 ---
buildCmd := &SubCommand{
Name: "build",
Description: "编译构建项目",
Flags: flag.NewFlagSet("build", flag.ContinueOnError),
}
var buildOutput string
// 在外部绑定参数,而不是在 Run 里面重新创建 FlagSet
buildCmd.Flags.StringVar(&buildOutput, "output", "./dist", "项目构建输出目录")
buildCmd.Run = func(args []string, global GlobalOptions) error {
if err := buildCmd.Flags.Parse(args); err != nil {
return err
}
fmt.Printf("[构建成功] 输出目录:%s,全局详细日志:%t,全局配置:%s\n",
buildOutput, global.Verbose, global.Config)
return nil
}
// --- 初始化 deploy 命令 ---
deployCmd := &SubCommand{
Name: "deploy",
Description: "部署项目到环境",
Flags: flag.NewFlagSet("deploy", flag.ContinueOnError),
}
var deployEnv string
deployCmd.Flags.StringVar(&deployEnv, "env", "dev", "部署环境 dev/test/prod")
deployCmd.Run = func(args []string, global GlobalOptions) error {
if err := deployCmd.Flags.Parse(args); err != nil {
return err
}
fmt.Printf("[部署成功] 目标环境:%s,全局配置文件:%s\n",
deployEnv, global.Config)
return nil
}
// 注册子命令
commands = map[string]*SubCommand{
"build": buildCmd,
"deploy": deployCmd,
}
}
func main() {
// 1. 初始化全局参数 FlagSet(独立隔离)
var global GlobalOptions
globalFlags := flag.NewFlagSet("global", flag.ContinueOnError)
globalFlags.BoolVar(&global.Verbose, "verbose", false, "启用详细日志输出")
globalFlags.StringVar(&global.Config, "config", "./config.yaml", "全局配置文件路径")
// 2. 解析全局参数
// 注意:flag 库遇到第一个非 Flag 参数(即子命令名称)就会停止解析
if err := globalFlags.Parse(os.Args[1:]); err != nil {
if err == flag.ErrHelp {
printHelp(globalFlags)
return
}
fmt.Println("全局参数解析失败:", err)
os.Exit(1)
}
// 3. 获取剩余参数(子命令 + 子命令参数)
remainingArgs := globalFlags.Args()
if len(remainingArgs) == 0 {
printHelp(globalFlags)
os.Exit(1)
}
// 4. 路由分发执行子命令
cmdName := remainingArgs[0]
if cmd, exists := commands[cmdName]; exists {
if err := cmd.Run(remainingArgs[1:], global); err != nil {
if err == flag.ErrHelp {
// 当子命令触发 -h 时,打印该子命令专属的帮助信息
fmt.Printf("\n===== 子命令 [%s] 帮助信息 =====\n", cmd.Name)
fmt.Printf("说明:%s\n\n用法:%s [选项]\n\n选项:\n", cmd.Description, cmd.Name)
cmd.Flags.PrintDefaults()
return
}
fmt.Printf("子命令执行失败:%v\n", err)
os.Exit(1)
}
} else {
fmt.Printf("❌ 未知子命令:%s\n", cmdName)
printHelp(globalFlags)
os.Exit(1)
}
}
// printHelp 统一打印全局帮助信息
func printHelp(globalFlags *flag.FlagSet) {
fmt.Println("===== 项目工程化 CLI 工具 =====")
fmt.Println("用法:tool [全局选项] <子命令> [子命令选项]")
fmt.Println("\n全局选项:")
globalFlags.PrintDefaults()
fmt.Println("\n可用子命令:")
for _, cmd := range commands {
fmt.Printf(" %-10s %s\n", cmd.Name, cmd.Description)
}
fmt.Println("\n提示:使用 'tool <子命令> -h' 查看子命令详细帮助")
}
+62
View File
@@ -0,0 +1,62 @@
package main
import (
"flag"
"fmt"
"time"
)
// CustomTime 自定义时间类型,复用标准库文本序列化接口
type CustomTime time.Time
// MarshalText 实现文本序列化(对应默认值展示)
func (t CustomTime) MarshalText() ([]byte, error) {
return []byte(time.Time(t).Format(time.RFC3339)), nil
}
// UnmarshalText 实现文本反序列化(参数解析核心)
func (t *CustomTime) UnmarshalText(b []byte) error {
parseTime, err := time.Parse(time.RFC3339, string(b))
if err != nil {
return err
}
*t = CustomTime(parseTime)
return nil
}
// 枚举类型示例:自定义运行模式
type RunMode string
const (
ModeDev RunMode = "dev"
ModeProd RunMode = "prod"
)
func (m RunMode) MarshalText() ([]byte, error) {
return []byte(m), nil
}
func (m *RunMode) UnmarshalText(b []byte) error {
val := RunMode(b)
if val != ModeDev && val != ModeProd {
return fmt.Errorf("非法运行模式,仅支持 dev/prod")
}
*m = val
return nil
}
func main() {
// 1. 自定义时间参数 TextVar 绑定
var execTime CustomTime
defaultTime := CustomTime(time.Now())
flag.TextVar(&execTime, "exec-time", defaultTime, "执行时间(RFC3339格式)")
// 2. 自定义枚举参数 TextVar 绑定
var runMode RunMode
flag.TextVar(&runMode, "mode", ModeDev, "运行模式 dev/prod")
flag.Parse()
fmt.Printf("运行模式:%s\n", runMode)
fmt.Printf("执行时间:%s\n", time.Time(execTime).Format(time.RFC3339))
}
+58
View File
@@ -0,0 +1,58 @@
package main
import (
"flag"
"fmt"
"os"
)
// PortValue 自定义端口类型,实现flag.Value接口
type PortValue int
func (p *PortValue) Set(s string) error {
var port int
_, err := fmt.Sscanf(s, "%d", &port)
if err != nil || port < 1 || port > 65535 {
return fmt.Errorf("非法端口,必须为1-65535整数")
}
*p = PortValue(port)
return nil
}
func (p *PortValue) String() string {
return fmt.Sprintf("%d", *p)
}
// EnvValue 枚举环境校验类型
type EnvValue string
func (e *EnvValue) Set(s string) error {
if s != "dev" && s != "prod" {
return fmt.Errorf("仅支持 dev/prod 环境")
}
*e = EnvValue(s)
return nil
}
func (e *EnvValue) String() string {
return string(*e)
}
func main() {
var port PortValue
var env EnvValue
flag.Var(&port, "port", "服务端口 1-65535")
flag.Var(&env, "env", "运行环境 dev/prod")
config := flag.String("config", "", "配置文件路径(必填)")
flag.Parse()
// 后置非空校验
if *config == "" {
fmt.Println("错误:config 参数不能为空")
flag.Usage()
os.Exit(1)
}
fmt.Printf("环境:%s,端口:%d,配置:%s\n", env, port, *config)
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 定义基础参数
flag.Int("port", 8080, "服务监听端口")
flag.String("host", "localhost", "服务绑定主机")
flag.Bool("debug", false, "开启调试模式")
// 解析参数
flag.Parse()
fmt.Println("=== 所有已定义参数(含默认值)===")
flag.VisitAll(func(f *flag.Flag) {
fmt.Printf("参数名:%-10s 默认值:%-10s 说明:%s\n", f.Name, f.DefValue, f.Usage)
})
fmt.Println("\n=== 用户主动传入的参数===")
flag.Visit(func(f *flag.Flag) {
fmt.Printf("参数名:%-10s 当前值:%-10s 已修改:%v\n", f.Name, f.Value.String(), f.Value.String() != f.DefValue)
})
}
+72
View File
@@ -0,0 +1,72 @@
package main
import "fmt"
// 定义函数类型(计算函数)
type Calculator func(int, int) int
// 实现加法
func add(a, b int) int {
return a + b
}
// 实现乘法
func multiply(a, b int) int {
return a * b
}
// 函数作为参数(策略模式)
func calculate(a, b int, op Calculator) int {
return op(a, b)
}
// 高阶函数:返回函数
func apply(f func(int) int, x int) int {
return f(x)
}
// 闭包:捕获外部变量
func makeAdder(base int) Calculator {
// 匿名函数捕获base
return func(a, b int) int {
return a + b + base
}
}
// 闭包:计数器
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
// 函数作为变量
var calc Calculator = add
fmt.Println("3+5=", calc(3, 5)) // 8
// 函数作为参数
fmt.Println("2*4=", calculate(2, 4, multiply)) // 8
// 高阶函数调用
double := func(x int) int { return x * 2 }
fmt.Printf("apply(4, double)=%d\n", apply(double, 4)) // 输出8
// 闭包示例
adder := makeAdder(10) // 基础值10
fmt.Println("1+2+10=", adder(1, 2)) // 13
// 计数器闭包
c1 := counter()
fmt.Printf("c1第1次: %d\n", c1()) // 输出1
fmt.Printf("c1第2次: %d\n", c1()) // 输出2
c2 := counter()
fmt.Printf("c2第1次: %d\n", c2()) // 输出1c1与c2的count独立)
// 错误示例
// var f func()
// f() // 报错:panic: runtime error: invalid memory address or nil pointer dereference
}
+48
View File
@@ -0,0 +1,48 @@
package main
import (
"log"
"net/http"
_ "net/http/pprof" // 注册pprof HTTP端点
"os"
"runtime"
"runtime/trace"
"time"
)
// simulateAlloc 模拟高频内存分配
func simulateAlloc() {
for {
_ = make([]byte, 1*1024*1024) // 每次分配1MB
time.Sleep(10 * time.Millisecond)
}
}
func main() {
// 1. 启动trace追踪,输出到文件
f, err := os.Create("gc_trace.out")
if err != nil {
log.Fatalf("创建trace文件失败: %v", err)
}
defer f.Close()
trace.Start(f)
defer trace.Stop()
// 2. 启动pprof HTTP服务(端口6060
go func() {
log.Println("pprof服务启动: http://localhost:6060/debug/pprof/")
log.Fatal(http.ListenAndServe(":6060", nil))
}()
// 3. 模拟内存分配压力
go simulateAlloc()
// 4. 运行30秒,积累诊断数据
log.Println("程序将运行30秒,可访问pprof分析GC...")
time.Sleep(30 * time.Second)
// 5. 打印最终GC状态
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
log.Printf("运行结束,GC总次数: %d,累计STW时长: %d ms", stats.NumGC, stats.PauseTotalNs/1e6)
}
+43
View File
@@ -0,0 +1,43 @@
package main
import (
"fmt"
"runtime"
"time"
)
// printGCStats 打印GC核心统计信息
func printGCStats() {
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Println("===== GC 统计信息 =====")
fmt.Printf("当前堆分配内存: %d MB\n", stats.Alloc/1024/1024) // 等价于HeapAlloc
fmt.Printf("存活使用堆内存: %d MB\n", stats.HeapInuse/1024/1024) // 真正的存活内存
fmt.Printf("空闲待回收内存: %d MB\n", stats.HeapIdle/1024/1024) // 垃圾内存
fmt.Printf("累计 STW 时长: %.3f ms\n", float64(stats.PauseTotalNs)/1e6)
fmt.Printf("GC 总次数: %d\n", stats.NumGC)
fmt.Printf("最近一次 STW 时长: %.3f μs\n", float64(stats.PauseNs[(stats.NumGC+255)%256])/1e3)
fmt.Printf("下一次GC触发阈值: %d MB\n", stats.NextGC/1024/1024) // 下次GC的内存阈值
fmt.Println("=======================\n")
}
func main() {
// 后台定时打印GC状态
go func() {
for {
printGCStats()
time.Sleep(3 * time.Second)
}
}()
// 模拟高频内存分配,触发GC
data := make([][]byte, 0)
for i := 0; i < 100; i++ {
data = append(data, make([]byte, 10*1024*1024)) // 每次分配10MB
time.Sleep(200 * time.Millisecond)
}
// 阻塞程序退出
select {}
}
+40
View File
@@ -0,0 +1,40 @@
package main
import (
"fmt"
"runtime"
)
// badFunc 局部大对象返回,触发逃逸
func badFunc() []byte {
buf := make([]byte, 1024*1024) // 1MB对象
return buf
}
// goodFunc 接收外部切片,复用内存,避免逃逸
func goodFunc(buf []byte) {
for i := range buf {
buf[i] = byte(i % 256)
}
}
func main() {
var stats runtime.MemStats
// 测试逃逸场景
runtime.GC()
for i := 0; i < 50; i++ {
_ = badFunc()
}
runtime.ReadMemStats(&stats)
fmt.Printf("逃逸场景:堆分配%d MBGC次数%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
// 测试避免逃逸场景
runtime.GC()
buf := make([]byte, 1024*1024) // 一次分配,复用
for i := 0; i < 50; i++ {
goodFunc(buf)
}
runtime.ReadMemStats(&stats)
fmt.Printf("避免逃逸:堆分配%d MBGC次数%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
}
+100
View File
@@ -0,0 +1,100 @@
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"runtime"
"sync"
"time"
)
// leakSlice 全局切片,持续追加数据导致内存泄漏
var leakSlice [][]byte
// generateLeak 模拟内存泄漏
func generateLeak() {
for {
// 每次分配10MB,追加到全局切片(永久引用,无法回收)
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
time.Sleep(100 * time.Millisecond)
// 打印当前内存状态
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("当前堆内存:%d MBGC次数:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
}
}
func generateLeak1() {
var maxMem uint64 = 500 // 最大允许占用500MB内存
for {
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
time.Sleep(100 * time.Millisecond)
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
curMem := stats.HeapAlloc / 1024 / 1024
fmt.Printf("当前堆内存:%d MBGC次数:%d\n", curMem, stats.NumGC)
// ✅ 核心修复:内存超限后,置空全局切片,切断引用
if curMem >= maxMem {
leakSlice = nil // 关键一行!置空后,原切片的所有[]byte都失去引用
runtime.GC() // 手动触发GC,立刻回收内存
fmt.Println("=== 内存超限,已释放所有内存 ===")
}
}
}
func generateLeak2() {
maxLen := 20 // 最多保留20个10MB切片,总内存上限200MB
for {
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
// ✅ 核心修复:超过最大长度,删除头部旧数据,释放引用
if len(leakSlice) > maxLen {
leakSlice = leakSlice[1:] // 切片切片,丢弃第一个元素,GC会回收它
}
time.Sleep(100 * time.Millisecond)
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("当前堆内存:%d MBGC次数:%d,切片长度:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC, len(leakSlice))
}
}
// ✅ 定义10MB切片的对象池
var needBytePool = sync.Pool{
New: func() interface{} {
return make([]byte, 10*1024*1024) // 每次创建10MB切片
},
}
// 无内存泄漏!复用内存,不持有永久引用
func generateLeak3() {
for {
// 从池子里拿切片,复用内存
buf := needBytePool.Get().([]byte)
// 模拟业务使用
_ = buf
// 使用完放回池子,供后续复用,释放引用
needBytePool.Put(buf[:0])
time.Sleep(100 * time.Millisecond)
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("当前堆内存:%d MBGC次数:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
}
}
func main() {
// 启动pprof服务
go func() {
log.Println("pprof服务启动:http://localhost:6060/debug/pprof/")
log.Fatal(http.ListenAndServe(":6060", nil))
}()
// 模拟内存泄漏
go generateLeak3()
// 运行60秒,便于诊断
time.Sleep(60 * time.Second)
}
+43
View File
@@ -0,0 +1,43 @@
package main
import (
"fmt"
"runtime"
"time"
)
// noPrealloc 未预分配容量,频繁扩容
func noPrealloc() {
var data []int
for i := 0; i < 100000; i++ {
data = append(data, i)
}
}
// withPrealloc 预分配容量,无扩容
func withPrealloc() {
data := make([]int, 0, 100000) // 预分配容量100000
for i := 0; i < 100000; i++ {
data = append(data, i)
}
}
func main() {
var stats runtime.MemStats
// 测试未预分配
runtime.GC()
start := time.Now()
noPrealloc()
dur1 := time.Since(start)
runtime.ReadMemStats(&stats)
fmt.Printf("未预分配:耗时%v,堆分配%d KBGC次数%d\n", dur1, stats.HeapAlloc/1024, stats.NumGC)
// 测试预分配
runtime.GC()
start = time.Now()
withPrealloc()
dur2 := time.Since(start)
runtime.ReadMemStats(&stats)
fmt.Printf("预分配:耗时%v,堆分配%d KBGC次数%d\n", dur2, stats.HeapAlloc/1024, stats.NumGC)
}
+73
View File
@@ -0,0 +1,73 @@
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
// 初始化1KB字节切片对象池
var bytePool = sync.Pool{
New: func() interface{} {
return make([]byte, 1024)
},
}
// 打印GC统计,衔接你之前的知识
func printGCStatsInfo(title string) {
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
fmt.Printf("[%s] GC次数: %d, 存活堆内存: %d KB\n", title, stats.NumGC, stats.HeapAlloc/1024)
}
// withoutPool 不使用对象池,频繁分配新内存
// 增加参数 []byte 模拟真实业务使用,禁止编译器消除代码
func withoutPool() time.Duration {
start := time.Now()
var temp []byte // 用于承接数据,避免死代码
for i := 0; i < 1000000; i++ { // 循环次数提升10倍,让耗时可被精准统计
buf := make([]byte, 1024)
temp = append(temp, buf...) // 模拟真实使用切片,编译器无法优化
}
_ = temp
return time.Since(start)
}
// withPool 使用对象池复用内存
func withPool() time.Duration {
start := time.Now()
var temp []byte // 用于承接数据,避免死代码
for i := 0; i < 1000000; i++ { // 同步提升循环次数
buf := bytePool.Get().([]byte)
temp = append(temp, buf...) // 模拟真实使用切片
bytePool.Put(buf[:0]) // 正确放回,保留你的最佳实践
}
_ = temp
return time.Since(start)
}
func main() {
// 预热并清空GC状态
runtime.GC()
printGCStatsInfo("初始化")
// 测试无对象池
dur1 := withoutPool()
printGCStatsInfo("无对象池后")
runtime.GC() // 强制GC,消除前序影响
// 测试有对象池
dur2 := withPool()
printGCStatsInfo("有对象池后")
// 增加分母非0判断,避免-Inf%
var rate float64
if dur1 > 0 {
rate = (1 - float64(dur2)/float64(dur1)) * 100
}
fmt.Printf("\n无对象池耗时: %v\n", dur1)
fmt.Printf("有对象池耗时: %v\n", dur2)
fmt.Printf("性能提升: %.2f%%\n", rate)
}
BIN
View File
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More