变量与类型

Go 的变量声明、基本类型与类型系统基础 一、变量声明 Go 是静态类型语言——变量的类型在编译时确定。 1.1 四种声明方式 // 1. var 显式声明(指定类型) var name string = "Go" // 2. var 显式声明(类型推断) var name = "Go" // 3. := 短变量声明(最常用,只能在函数内使用) name := "Go" // 4. var 批量声明 var ( age int = 25 height float64 = 175.5 isGo bool = true ) 1.2 := 的限制 // ✅ 函数内部 — 可以用 := func main() { x := 10 fmt.Println(x) } // ❌ 包级别 — 不能用 :=,必须用 var var globalVar = "ok" // globalVar := "fail" // 编译错误 1.3 零值 Go 中未赋值的变量自动初始化为零值(不是 undefined 或 null): ...

2026 年 10 月 13 日

标准库核心包:fmt / strings / os / io / time

从 C++ 的 iostream / string / fstream / chrono 到 Go 标准库核心包 一、简述 Go 标准库是"开箱即用"的典范——网络、JSON、加密、压缩、时间、文件全都在标准库里。本笔记聚焦日常开发最高频的 5 个包:fmt(格式化)、strings(字符串)、os(文件/环境)、io(读写抽象)、time(时间)。 核心要点:这些包配合 Go 的"接口即抽象"哲学(io.Reader / io.Writer),形成了统一的数据流处理模型——你写的函数只需要面向接口,就能处理文件、内存、网络任何来源。 二、C++ 对照速查表 概念 C++ Go 关键差异 格式化输出 std::cout << x fmt.Println(x) Go 内置格式动词 格式化字符串 sprintf(buf, "%d", x) fmt.Sprintf("%d", x) 返回 string,无缓冲区 字符串操作 std::string / <cstring> strings 包 函数式,无成员方法 字符串拼接 s1 + s2 strings.Join / strings.Builder 大量拼接用 Builder 文件读取 std::ifstream os.Open + io.ReadAll 接口化 文件写入 std::ofstream os.WriteFile 一键写整个文件 时间获取 std::chrono::system_clock::now() time.Now() 返回 Time 结构体 休眠 std::this_thread::sleep_for time.Sleep 用法相似 计时 std::chrono::duration time.Since(t) 返回 Duration 三、fmt —— 格式化 3.1 输出函数 fmt.Print("a", "b") // 无换行、无空格: ab fmt.Println("a", "b") // 空格分隔 + 换行: a b fmt.Printf("%s %d", "go", 1) // 格式化: go 1 // 返回字符串版本 s := fmt.Sprintf("%s-%d", "v", 3) // "v-3" 3.2 常用格式动词 动词 含义 示例 %v 默认格式(任意类型) fmt.Printf("%v", 42) %+v 结构体带字段名 fmt.Printf("%+v", p) → {Name:tom Age:18} %#v Go 语法表示 fmt.Printf("%#v", p) → main.Person{Name:"tom"} %T 类型 fmt.Printf("%T", 42) → int %d 十进制整数 42 %x 十六进制 2a %f / %.2f 浮点 / 保留两位 3.14 / 3.14 %s 字符串 "hello" %q 带引号字符串 "hello" %t 布尔 true %p 指针地址 0xc0000b2000 3.3 对齐与宽度 fmt.Printf("%-10s|%10s\n", "left", "right") // left | right fmt.Printf("%05d\n", 42) // 00042(前导零) 四、strings —— 字符串处理 Go 的 string 是不可变值类型,所有操作都返回新字符串。 ...

2026 年 10 月 13 日

并发编程基础

Goroutine、Channel、Select——Go 并发的核心原语 一、Goroutine 1.1 什么是 Goroutine Goroutine 是 Go 运行时管理的轻量级线程。创建成本极低(约 2KB 栈空间),可以轻松创建成千上万个。 // 启动一个 goroutine:在函数调用前加 go 关键字 go doSomething() go func() { fmt.Println("running in goroutine") }() 1.2 基本使用 package main import ( "fmt" "time" ) func printNumbers() { for i := 1; i <= 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Printf("number: %d\n", i) } } func printLetters() { for i := 'a'; i <= 'e'; i++ { time.Sleep(150 * time.Millisecond) fmt.Printf("letter: %c\n", i) } } func main() { go printNumbers() // 并发执行 go printLetters() // 并发执行 time.Sleep(2 * time.Second) // 等待 goroutine 完成 fmt.Println("done") } // 输出交错出现:number: 1, letter: a, number: 2, letter: b... 1.3 主 Goroutine 与 WaitGroup 上面用 time.Sleep 等待是不可靠的。正确做法是用 sync.WaitGroup: ...

2026 年 10 月 13 日

并发模式(worker pool / 扇入扇出 / pipeline)

C++ 里要自己造轮子的线程池、任务队列、流水线,Go 用 channel 组合出几种固定范式,一次学会受用终生 一、简述 「并发模式」不是语法,而是被反复验证有效的编排范式。Go 里它们几乎全由 channel + goroutine 组合而成:worker pool(工人池)、fan-out(扇出)、fan-in(扇入 / 汇聚)、pipeline(流水线)、限速器(rate limit)、错误传播。 对于 C++ 开发者,这些模式你多半见过、也手动实现过: 模式 C++ 里怎么做的 痛点 线程池 std::thread 数组 + std::queue 任务 + mutex 守卫 线程生命周期、任务派发、锁竞争都要自己管 扇出 把一个大任务拆 N 份发给 N 线程 怎么「等所有分片」+ 汇总 流水线 每个 stage 一个线程 + 队列 + condvar 关停时机难管 限速 令牌桶 / 手写信号量 又要造一个计数器 + 条件变量 Go 里这些平均不到 30 行,且语义全部显式可见。本笔记不讲抽象,直接给 6 个能 go run 的模板。 核心要点:所有模式都建立在「channel 即队列 + 同步」之上。模式 = 固定形状的 channel 拓扑 + 一组约定(谁 close、谁 range、谁 Wait)。 ...

2026 年 10 月 13 日

测试:单元、表格驱动、基准、覆盖率

从 C++ 的 GTest 到 Go testing 标准库:约定优于配置,表格驱动是 Go 的灵魂测试法 一、简述 Go 把测试框架内置为标准库 testing,零配置、约定驱动:文件以 _test.go 结尾,函数名 TestXxx(t *testing.T) 即被测对象。不需要 GTest 那样的宏和注册表,go test 一条命令跑全部测试。 C++ 开发者上手 GTest 要经历「链接 gtest、写 TEST 宏、配 CMake、起 runner」;Go 则是「建 _test.go、写 func TestXxx(t *testing.T)、go test」。**表格驱动测试(table-driven tests)**是 Go 社区最推崇的测试形态——本质是把断言与数据分离,让测试用例变成一张表。 核心要点:testing 包只给了「基础骨架」(t 的各种方法),断言与 mock 不内置——这是 Go 的极简哲学。但配合表格驱动 + 子测试 + 基准 + 覆盖率,能覆盖绝大多数项目需求。 二、C++ 对照速查表 概念 C++ Go 关键差异 测试框架 GoogleTest / Catch2(第三方) testing 标准库 零依赖、零配置,go test 即跑 测试文件 test_xxx.cpp xxx_test.go 命名约定即可被发现 测试用例 TEST(Suite, Name) func TestXxx(t *testing.T) 编译期自动收集,无宏无注册 断言 EXPECT_EQ / ASSERT_EQ t.Errorf / t.Fatal Go 里就是普通方法调用 致命 vs 非致命 ASSERT(终止)vs EXPECT(继续) t.Fatal(终止)vs t.Errorf(继续) 语义一一对应 子测试 SCOPED_TRACE 近似 t.Run("name", ...) 自带层级输出、可独立筛选运行 表格驱动 GTEST 参数化 P 复杂 切片 + for 循环 语言特性天然支持,无需框架 基准测试 Google Benchmark BenchmarkXxx(b *testing.B) + b.N benchmark 内建 覆盖率 -fprofile-arcs + gcov/lcov go test -cover 一条命令带 HTML 输出 数据竞态检测 TSan(需编译期开启) go test -race 运行时内建,跨平台 三、逐主题详解 3.1 单元测试最小形态 在 calc.go 旁边放 calc_test.go: ...

2026 年 10 月 13 日

测试与工程实践

Go 的内置测试框架、代码规范与工程化实践 一、单元测试 1.1 测试文件命名 // 测试文件以 _test.go 结尾 math.go → math_test.go user.go → user_test.go utils/string.go → utils/string_test.go 1.2 基本测试函数 // math.go package math func Add(a, b int) int { return a + b } // math_test.go package math import "testing" func TestAdd(t *testing.T) { result := Add(1, 2) if result != 3 { t.Errorf("Add(1, 2) = %d; want 3", result) } } // 运行测试 // go test ./... // go test -v ./...(详细输出) 1.3 Table-Driven Tests(表驱动测试) Go 社区最推崇的测试模式: func TestAdd(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 1, 2, 3}, {"negative numbers", -1, -2, -3}, {"zero", 0, 0, 0}, {"mixed", -1, 1, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Add(tt.a, tt.b) if result != tt.expected { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected) } }) } } // 运行特定子测试 // go test -run TestAdd/positive_numbers 1.4 测试辅助函数 // 断言辅助函数(Go 标准库没有内置 assert,但可以自己写) func assertEqual(t *testing.T, got, want interface{}) { t.Helper() // 标记为辅助函数,错误信息显示调用者行号 if got != want { t.Errorf("got %v, want %v", got, want) } } func TestAdd(t *testing.T) { assertEqual(t, Add(1, 2), 3) } t.Helper():标记辅助函数,错误时显示调用方的行号而非辅助函数内部行号。 ...

2026 年 10 月 13 日

常用工具 gofmt/vet/doc/交叉编译

从 clang-format/clang-tidy/doxygen 到 Go 内建工具链:规范靠工具强制,而非风格文档 一、简述 Go 的工具链是「一个 go 命令 + 若干子命令」的整体。gofmt 统一代码格式、go vet 做静态检查、go doc 生成/查看文档、go build 配合环境变量实现交叉编译。与 C++ 需要 clang-format + clang-tidy + doxygen + 一堆脚本不同,Go 把规范内置——gofmt 的格式无人争论,因为唯一标准。 核心要点:gofmt 从 Go 项目诞生起就存在,go fmt 只是 go 工具链对它的子命令封装,两者格式化结果一致;真正的工程价值是让「风格讨论」从代码评审里消失——C++ 团队为空格和括号开过的会,在 Go 里不存在。 二、C++ 对照速查表 概念 C++ Go 关键差异 代码格式化 clang-format(需 .clang-format 配置) gofmt / go fmt 零配置,官方唯一风格 静态检查 clang-tidy / cppcheck go vet 内建,覆盖导入/函数调用等 文档生成 doxygen(注释标记 + 配置) go doc + godoc 注释即文档,无需单独构建 文档注释风格 ///、块注释 + doxygen 指令 成对注释(块首选) // 名称 描述 约定,导出符号必须注释 交叉编译 每平台一套交叉工具链/CI GOOS=linux GOARCH=amd64 go build 一条命令 + 环境变量 静态链接 -static / 静态库手动组合 CGO_ENABLED=0 默认即可产纯静态二进制 精简体积 -s strip 符号 -ldflags "-s -w" 编译期传递 linker 参数 依赖清理 CMake/vcpkg 手工重配 go mod tidy 与工具链一体 三、逐主题详解 3.1 gofmt / go fmt:官方格式 # 查看差异(不修改) gofmt -l . # 列出格式不达标的文件 gofmt -d file.go # 输出 diff 视角的差异 # 覆盖写文件 gofmt -w file.go go fmt ./... # 等价于 gofmt -w,作用于当前包全部 .go # gofmt 不影响语义:只重排缩进、对齐、换行、导入块 关键规则(你不需要背,工具会改): ...

2026 年 10 月 13 日

错误处理

Go 的错误处理哲学:error 是值,不是异常 一、Go 的错误处理哲学 1.1 与异常机制的区别 特性 Go(error) Java/Python(异常) 表现形式 普通返回值 try-catch 机制 调用开销 零(就是多返回一个值) 较高(栈展开) 强制处理 编译器检查(必须处理) 可以不 catch 可预测性 高——每个可能出错的地方都明确 低——调用链可能随时抛异常 1.2 核心原则 // Go 的错误处理模式:每个可能出错的调用都检查返回值 result, err := doSomething() if err != nil { // 处理错误:记录日志、返回错误、终止程序等 return fmt.Errorf("doSomething failed: %w", err) } // 继续正常逻辑 Go 的哲学:显式胜于隐式。 没有隐藏的控制流,错误路径一目了然。 二、error 接口 2.1 error 的定义 // 标准库中 error 的定义(非常简洁) type error interface { Error() string } 任何实现了 Error() string 方法的类型都是一个 error: // 自定义错误类型 type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation failed on field '%s': %s", e.Field, e.Message) } // 使用 err := &ValidationError{Field: "email", Message: "invalid format"} fmt.Println(err) // validation failed on field 'email': invalid format 2.2 创建错误的几种方式 import ( "errors" "fmt" ) // 1. errors.New:简单的静态错误消息 var ErrNotFound = errors.New("not found") // 使用时 if err == ErrNotFound { // 处理特定错误 } // 2. fmt.Errorf:格式化错误消息(最常用) err := fmt.Errorf("user %d not found", userID) // 3. %w 动词:包装(wrap)另一个错误 func getUser(id int) (*User, error) { err := db.Query("...") if err != nil { return nil, fmt.Errorf("getUser(%d): %w", id, err) // %w 保留了原始错误,可以用 errors.Is/As 检查 } return &user, nil } // 4. 自定义错误类型(携带结构化信息) // 见上方 ValidationError 示例 三、错误处理模式 3.1 基本模式 // 模式1:检查并返回 func processFile(path string) error { data, err := os.ReadFile(path) if err != nil { return fmt.Errorf("reading %s: %w", path, err) } // 处理 data... return nil // 成功时返回 nil } // 模式2:检查并记录日志 + 继续 data, err := fetchConfig() if err != nil { log.Printf("config fetch failed, using defaults: %v", err) data = defaultConfig() } // 模式3:检查并终止 file, err := os.Open("critical.txt") if err != nil { log.Fatal("无法打开关键文件:", err) } defer file.Close() 3.2 错误链(Error Wrapping) Go 1.13+ 支持错误包装,可以构建错误链: ...

2026 年 10 月 13 日

错误处理:error / panic / recover

从 C++ 的 try/catch/throw 到 Go 的显式错误返回值、panic 与 defer+recover 一、简述 Go 的错误处理哲学和 C++ 完全相反:不抛异常,而是把错误当作普通返回值显式传递。函数签名里直接写明"可能返回错误",调用方必须处理。这套设计的核心目标:错误路径在代码里一目了然,绝不静默吞掉。 Go 提供三层错误机制: 机制 用途 类似 C++ error 返回值 可预期、应处理的错误(文件不存在、网络失败…) 返回码 / std::error_code panic 不可恢复的严重错误(越界、空指针…) throw recover 在 defer 中捕获 panic catch 核心要点:能用 error 就不要 panic。panic 是"程序无法继续"的最后手段,recover 只用于极少数场景(如防止 goroutine 崩溃拖垮整个程序)。 二、C++ 对照速查表 概念 C++ Go 关键差异 抛出错误 throw std::runtime_error("...") return errors.New("...") Go 是返回值,不是跳转 捕获错误 try { } catch (const std::exception& e) if err != nil { ... } Go 用 if 判断 错误类型 异常类层级 error 接口 Go 只有一个 error 接口 清理资源 RAII / 析构 defer 函数级,非作用域级 致命错误 std::terminate panic 都是不可恢复 兜底捕获 catch (...) defer func() { recover() }() recover 必须在 defer 中 错误包装 异常嵌套 fmt.Errorf("%w", err) %w 支持解包判断 三、error 接口 Go 的 error 是一个预定义接口: ...

2026 年 10 月 13 日

达梦数据库学习路线(Qt/C++ 电力运维场景)

背景定位 电力设备运维场景:变电站设备经 IEC 104 规约报文上送遥测/遥信数据,需要采集、解析并落库存储。 Qt/C++ 开发背景(Qtc++):以 Qt 技术栈(MVC、QSqlDatabase、ODBC)为主线承载数据库操作与界面联动。 国产数据库达梦(DM8)学习:从连接、SQL 到运维全链路,教学过程中与 MySQL 持续对比,突出差异。 业务代码可用伪代码表述,重点放在数据库讲解的详细性上(驱动、连接、语法、事务、运维)。 章节规划 编号 标题 内容 状态 01 Qt-MVC与达梦数据库集成 QSqlTableModel/QSqlQueryModel/QSqlRelationalTableModel + ODBC 连接达梦,报文解析→落库→界面刷新链路 ✅ 已写 02 连接与驱动 ODBC 驱动安装、连接串、QSqlDatabase 建立流程、达梦 COMPATIBLE_MODE 兼容模式 ⬜ 待写 03 基础SQL与MySQL对比 数据类型、建库建表、CRUD、达梦特有语法(如 DUAL、序列)、MySQL 迁移工具 ⬜ 待写 04 IEC104规约报文实战 104 规约帧格式详解、报文解析、达梦落库、与界面联动 ⬜ 待写 05 进阶-事务与运维 事务隔离级别、存储过程/触发器、备份恢复、性能优化、达梦集群 ⬜ 待写 学习路径建议 先读 01 建立「报文→数据库→界面」整体认识,理解全链路数据流向。 再补 02/03 打牢连接与 SQL 基础,掌握 ODBC 驱动与达梦语法特性。 04 回到报文实战深挖规约,将解析与落库结合,完成闭环。 05 面向生产运维,覆盖事务、存储过程与备份恢复等工程落地能力。 进度表 当前进度:01 已写,其余四章待写,按上表顺序推进。 本路线图随笔记进度持续更新,每完成一章即同步修订状态列。

2026 年 10 月 13 日