go标准库入门
fmt包 详细讲解
一、核心定位
fmt 是 Go 标准库(standard library)中最基础的 输入输出包(format 的缩写),用于实现程序与控制台、文件等的格式化输入输出,是入门阶段最常用的标准库之一,无需额外下载,直接导入即可使用。
二、导入方式
1. 基础导入(最常用)
import "fmt"
- 作用:将 fmt 包完整导入,使用时需通过 fmt. 前缀调用包内函数(如 fmt.Println)。
- 场景:需要使用 fmt 包的多个功能(如输入、输出、格式化)时。
2. 别名导入
import f "fmt" // 给 fmt 取别名 f
- 作用:给包起简短别名,简化调用(如 f.Println(“Hello”))。
- 场景:包名过长或避免命名冲突时(实际开发中 fmt 极少用别名,示例仅作演示)。
import _ "fmt"
- 作用:仅执行 fmt 包的初始化函数(init 函数),不直接调用包内函数。
- 注意:fmt 包的初始化无特殊副作用,此方式几乎不用,仅作语法说明。
三、核心功能与实战示例
1. 输出功能(重点)
用于将数据打印到控制台(默认标准输出),核心函数分 普通输出 和 格式化输出 两类。
(1)普通输出:快速打印
|
函数 |
功能说明 |
示例 |
输出结果 |
|
|
打印数据,不自动换行,数据间无分隔符 |
fmt.Print(“Go”, 123) |
Go123 |
|
Println |
打印数据,自动换行,数据间自动加空格 |
fmt.Println(“Go”, 123) |
Go 123(换行) |
|
Printf |
格式化打印,按指定格式输出,不自动换行 |
fmt.Printf(“语言:%s,版本:%d”, “Go”, 1) |
语言:Go,版本:1 |
2)格式化输出:精准控制格式
Printf 依赖 格式占位符 控制输出样式,常用占位符如下:
基础类型占位符:
- %v:通用占位符,适配任意类型(推荐优先使用);
- %d:十进制整数(int 系列);
- %s:字符串;
- %f:浮点数(默认保留 6 位小数);
- %t:布尔值(true/false);
- %p:指针地址(十六进制)。
示例:
package main
import "fmt"
func main() {
name := "Go开发者"
age := 3
score := 95.5
isPass := true
ptr := &name // 取name的指针
// 格式化输出组合数据
fmt.Printf("姓名:%s,年龄:%d,成绩:%.1f,是否通过:%t,指针地址:%p
",
name, age, score, isPass, ptr)
// 输出:姓名:Go开发者,年龄:3,成绩:95.5,是否通过:true,指针地址:0xc00008a240
}
2. 输入功能
用于从控制台(默认标准输入)读取用户输入,核心函数是 Scan 系列。
(1)基础输入:Scan
package main
import "fmt"
func main() {
var name string
var age int
// 读取用户输入,按空格/回车分隔数据,依次赋值给name和age
fmt.Print("请输入姓名和年龄:")
fmt.Scan(&name, &age) // &表明取变量地址,确保输入值能写入变量
fmt.Printf("你输入的是:姓名=%s,年龄=%d
", name, age)
}
- 运行后输入 张三 25,输出:你输入的是:姓名=张三,年龄=25。
(2)格式化输入:Scanf
按指定格式读取输入,适配复杂场景(如指定输入包含特定字符):
package main
import "fmt"
func main() {
var score float64
fmt.Print("请输入成绩(格式:分数=XX.X):")
fmt.Scanf("分数=%f", &score) // 仅读取"分数="后的浮点数
fmt.Printf("成绩是:%.1f
", score)
}
- 运行后输入 分数=98.5,输出:成绩是:98.5。
(3)读取整行输入:Scanln
读取一行输入(遇到回车结束),常用于读取包含空格的字符串:
package main
import "fmt"
func main() {
var address string
fmt.Print("请输入地址:")
fmt.Scanln(&address) // 读取整行,包含空格
fmt.Printf("地址:%s
", address)
}
- 运行后输入 北京市朝阳区,输出:地址:北京市朝阳区。
3. 其他实用功能
(1)错误输出:Fprintf输出到标准错误流
package main
import "fmt"
import "os"
func main() {
// 输出错误信息到标准错误流(控制台会显示为红色,区分普通输出)
fmt.Fprintf(os.Stderr, "错误:除数不能为0
")
}
(2)字符串格式化:Sprintf生成格式化字符串
不直接打印,而是返回格式化后的字符串,用于后续处理:
package main
import "fmt"
func main() {
// 生成格式化字符串
info := fmt.Sprintf("用户:%s,等级:%d", "小明", 5)
// 后续使用字符串(如拼接、存储)
fmt.Println("用户信息:" + info) // 输出:用户信息:用户:小明,等级:5
}
四、实战注意事项
- 地址传递:Scan 系列函数必须传入变量地址(&变量名),否则无法修改变量值(Go 是值传递,不传地址仅操作副本)。
- 格式化占位符匹配:Printf 的占位符类型必须与传入参数类型一致(如 %d 对应 int,不能传字符串),否则会输出错误值。
- 浮点数精度控制:%f 可通过 %.nf 控制小数位数(n 为位数),如 %.2f 保留 2 位小数。
- 标准库特性:fmt 是标准库,无需 go get 安装,直接导入即可;升级 Go 版本时,fmt 包的 API 基本保持兼容,稳定性极高。
os 包:简单文件操作(创建、读取、删除文件)详细讲解
一、核心定位
os 是 Go 标准库中用于 操作系统交互 的核心包,文件操作是其最常用的功能之一,支持创建、读取、删除、重命名等基础文件操作,无需额外依赖,直接导入即可使用。
二、关键前置概念
- 文件路径:Windows 系统支持两种格式(C: estfile.txt 或 /test/file.txt,Go 可兼容处理);
- 文件权限:Windows 下主要依赖系统权限控制,Go 中创建文件时指定的权限参数(如 0644)会自动适配系统规则;
- 错误处理:os 包函数大多返回 error 类型,必须通过 if err != nil 判断操作是否成功,避免遗漏异常。
三、核心文件操作详解(附代码示例)
所有示例均需导入 os 包和 fmt 包(用于输出和错误打印),基础代码框架:
package main
import (
"fmt"
"os"
)
func main() {
// 具体操作代码放在这里
}
1. 文件创建:创建新文件
支持两种常用方式:Create(直接创建空文件,存在则覆盖)和 OpenFile(更灵活,支持指定创建模式)。
(1)基础创建:os.Create
- 功能:创建指定路径的文件,若文件已存在则 清空原有内容并覆盖;
- 返回值:*os.File(文件对象,用于后续操作)和 error(错误信息)。
示例:
func main() {
// 创建文件:路径可自定义,如 "C:\test\demo.txt" 或 "./demo.txt"(当前目录)
file, err := os.Create("demo.txt")
if err != nil {
fmt.Printf("创建文件失败:%v
", err)
return
}
defer file.Close() // 关键:函数结束前关闭文件,释放资源(defer 延迟执行)
fmt.Println("文件创建成功!")
}
(2)灵活创建:os.OpenFile
- 功能:支持指定创建模式(如 “不存在则创建、存在则追加”),更适配复杂场景;
- 核心参数:path(路径)、flag(模式标志)、perm(权限,Windows 下可填 0644 默认值)。
常用模式标志:
- os.O_CREATE:不存在则创建;当文件不存在时,会自动创建一个新的文件
- os.O_WRONLY:只写模式;只能向文件写入数据,不能读取
- os.O_APPEND:追加模式(不覆盖原有内容);每次写入文件的数据都会自动添加到文件末尾,而不会覆盖原有内容。
- os.O_TRUNC:清空模式(覆盖原有内容)。
- 可以组合使用
示例(创建并追加内容):
func main() {
// 组合模式:不存在则创建 + 只写 + 追加内容
file, err := os.OpenFile("demo.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Printf("创建文件失败:%v
", err)
return
}
defer file.Close()
// 向文件写入内容(后续“写入”章节详解)
_, err = file.WriteString("这是追加的内容
")
if err != nil {
fmt.Printf("写入失败:%v
", err)
return
}
fmt.Println("文件创建并追加内容成功!")
}
2. 文件读取:读取文件内容
支持三种常用场景:读取全部内容、按字节读取、按行读取,根据文件大小选择合适方式。
(1)读取全部内容:os.ReadFile(最简洁)
- 功能:一次性读取文件所有内容,返回字节切片([]byte),无需手动打开 / 关闭文件(内部已封装);
- 适用场景:小文件(如配置文件、日志片段)。
示例:
func main() {
// 读取文件全部内容
content, err := os.ReadFile("demo.txt")
if err != nil {
fmt.Printf("读取文件失败:%v
", err)
return
}
// 字节切片转字符串输出
fmt.Println("文件内容:")
fmt.Println(string(content))
}
(2)按字节读取:os.Open + File.Read(灵活控制)
- 功能:打开文件后手动控制读取字节数,适合大文件(避免一次性加载占用过多内存);
- 步骤:os.Open(打开文件)→ File.Read(循环读取)→ File.Close(关闭文件)。
示例:
func main() {
// 打开文件(只读模式,默认)
file, err := os.Open("demo.txt")
if err != nil {
fmt.Printf("打开文件失败:%v
", err)
return
}
defer file.Close()
// 定义缓冲区(每次读取 1024 字节)
buf := make([]byte, 1024)
fmt.Println("文件内容:")
for {
// 读取内容到缓冲区,n 为实际读取的字节数
n, err := file.Read(buf)
if err != nil {
// 读取到末尾时会返回 io.EOF 错误,属于正常结束
if err.Error() == "EOF" {
break
}
fmt.Printf("读取失败:%v
", err)
return
}
// 输出本次读取的内容(只取实际读取的 n 字节)
fmt.Print(string(buf[:n]))
}
}
defer file.Close() 会在 main() 函数即将返回时执行,无论函数是正常结束还是因错误提前返回。
3)按行读取:结合 bufio 包(文本文件常用)
os 包本身不直接支持按行读取,需配合标准库 bufio 包实现,适合读取日志、配置等文本文件。
示例:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Open("demo.txt")
if err != nil {
fmt.Printf("打开文件失败:%v
", err)
return
}
defer file.Close()
// 创建按行读取的扫描器
scanner := bufio.NewScanner(file)
lineNum := 1
fmt.Println("文件内容(按行):")
// 循环扫描每一行
for scanner.Scan() {
line := scanner.Text() // 获取当前行内容
fmt.Printf("%d: %s
", lineNum, line)
lineNum++
}
// 检查扫描过程是否出错
if err := scanner.Err(); err != nil {
fmt.Printf("按行读取失败:%v
", err)
}
}
3. 文件写入:向文件写入内容
基于创建文件返回的 *os.File 对象操作,支持写入字节切片或字符串。
(1)基础写入:File.Write/ File.WriteString
- File.Write:写入字节切片([]byte);
- File.WriteString:直接写入字符串(更直观,内部自动转字节切片)。
示例:
func main() {
// 打开文件:不存在则创建,存在则清空(覆盖)
file, err := os.OpenFile("demo.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
fmt.Printf("打开文件失败:%v
", err)
return
}
defer file.Close()
// 写入字符串
_, err = file.WriteString("第一行内容
")
if err != nil {
fmt.Printf("写入失败:%v
", err)
return
}
// 写入字节切片
data := []byte("第二行内容(字节切片)
")
_, err = file.Write(data)
if err != nil {
fmt.Printf("写入失败:%v
", err)
return
}
fmt.Println("写入内容成功!")
}
(2)批量写入:File.WriteAt(指定位置写入)
- 功能:在文件的指定字节位置写入内容,可用于修改文件中间部分(需提前知道内容位置)。
示例:
func main() {
file, err := os.OpenFile("demo.txt", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
fmt.Printf("打开文件失败:%v
", err)
return
}
defer file.Close()
// 先写入基础内容
file.WriteString("Hello World!")
// 在索引 6 的位置(即 "World" 开头)写入 "Go "
file.WriteAt([]byte("Go "), 6)
// 读取验证:最终内容为 "Hello Go!"
content, _ := os.ReadFile("demo.txt")
fmt.Println(string(content)) // 输出:Hello Go!
}
4. 文件删除:删除指定文件
使用 os.Remove 函数,直接传入文件路径即可,需注意:删除后无法恢复,提议先判断文件是否存在。
示例:
func main() {
filePath := "demo.txt"
// 可选:先判断文件是否存在
_, err := os.Stat(filePath)
if os.IsNotExist(err) {
fmt.Printf("文件不存在:%s
", filePath)
return
}
// 执行删除
err = os.Remove(filePath)
if err != nil {
fmt.Printf("删除文件失败:%v
", err)
return
}
fmt.Printf("文件 %s 删除成功!
", filePath)
}
5. 额外实用操作
(1)判断文件 / 目录是否存在:os.Stat + os.IsNotExist
func main() {
path := "demo.txt"
_, err := os.Stat(path)
if os.IsNotExist(err) {
fmt.Printf("%s 不存在
", path)
} else if err != nil {
fmt.Printf("判断失败:%v
", err)
} else {
fmt.Printf("%s 存在
", path)
}
}
(2)重命名文件:os.Rename
func main() {
oldPath := "demo.txt"
newPath := "new_demo.txt"
err := os.Rename(oldPath, newPath)
if err != nil {
fmt.Printf("重命名失败:%v
", err)
return
}
fmt.Printf("文件已从 %s 重命名为 %sn", oldPath, newPath)
}
四、实战注意事项
- 资源释放:所有通过 os.Open/os.Create/os.OpenFile 打开的文件,必须通过 defer file.Close() 延迟关闭,避免资源泄漏;
- 路径处理:Windows 下路径中的反斜杠 需转义(写成 \),或直接使用正斜杠 /(Go 自动兼容);
- 大文件处理:避免用 os.ReadFile 读取超大文件(如几十 GB 的日志),应使用 os.Open + 循环读取 分块处理;
- 权限问题:若操作系统目录(如 C:Windows),需以 管理员身份 运行程序,否则会返回权限不足错误;
- 错误细分:通过 os.IsNotExist(err) 可判断 “文件不存在” 错误,通过 os.IsPermission(err) 可判断 “权限不足” 错误,便于精准处理异常。
五、实战小案例:简单文本文件读写工具
功能:创建文件 → 写入内容 → 读取内容 → 重命名 → 最终删除,串联核心操作:
package main
import (
"fmt"
"os"
)
func main() {
// 1. 创建并写入内容
file, err := os.Create("test.txt")
if err != nil {
fmt.Printf("创建失败:%v
", err)
return
}
file.WriteString("这是测试内容
")
file.Close()
fmt.Println("1. 创建并写入成功")
// 2. 读取内容
content, _ := os.ReadFile("test.txt")
fmt.Println("2. 读取内容:", string(content))
// 3. 重命名
os.Rename("test.txt", "test_rename.txt")
fmt.Println("3. 重命名为 test_rename.txt")
// 4. 删除文件
os.Remove("test_rename.txt")
fmt.Println("4. 删除文件成功")
}
strconv 包:字符串与基本类型转换
一、核心定位
strconv 是 Go 标准库中用于 字符串与基本数据类型(整型、浮点型、布尔型等)相互转换 的核心包,解决了不同类型数据间的格式适配问题,是开发中高频使用的工具类包,无需额外依赖,直接导入即可使用。
二、关键前置概念
- 转换方向:分为 “基本类型转字符串” 和 “字符串转基本类型” 两类,需根据场景选择对应函数;
- 错误处理:字符串转基本类型时,若字符串格式不匹配(如 “abc” 转整型)会返回错误,必须通过 if err != nil 处理;
- 进制与精度:整型转字符串支持指定进制(2-36 进制),浮点型转换支持指定精度,适配多样化需求。
三、核心转换功能详解(附代码示例)
所有示例需导入 strconv 包和 fmt 包,基础框架:
package main
import (
"fmt"
"strconv"
)
func main() {
// 具体转换代码
}
1. 字符串与整型转换(最常用)
支持
int/int8/int16/int32/int64 与字符串的双向转换,其中 int64 转换函数(Atoi/Itoa 底层依赖)需重点掌握。
(1)整型转字符串:Itoa 与 FormatInt
- 基础转换:strconv.Itoa
其命名源于 Int to ASCII 的缩写,直观对应函数功能 —— 将整型(int)转换为字符串(ASCII 字符序列)。
- 功能:将 int 类型转为字符串,是 FormatInt(int64(i), 10) 的简化版(默认十进制)。
- 示例:
func main() {
num1 := 123
num2 := -456
// 整型转字符串
str1 := strconv.Itoa(num1)
str2 := strconv.Itoa(num2)
fmt.Printf("类型:%T,值:%s
", str1, str1) // 类型:string,值:123
fmt.Printf("类型:%T,值:%s
", str2, str2) // 类型:string,值:-456
}
灵活转换:strconv.FormatInt
功能:将 int64 类型转为字符串,支持指定进制(2-36 进制,超过 10 进制用字母 a-z 表明)。示例(多进制转换):
func main() {
num := int64(255)
// 十进制转字符串
decStr := strconv.FormatInt(num, 10)
// 二进制转字符串
binStr := strconv.FormatInt(num, 2)
// 十六进制转字符串(小写字母)
hexStr := strconv.FormatInt(num, 16)
// 三十六进制转字符串(0-9+a-z)
hex36Str := strconv.FormatInt(num, 36)
fmt.Println("十进制:", decStr) // 十进制:255
fmt.Println("二进制:", binStr) // 二进制:11111111
fmt.Println("十六进制:", hexStr) // 十六进制:ff
fmt.Println("三十六进制:", hex36Str) // 三十六进制:73
}
(2)字符串转整型:Atoi 与 ParseInt
- 基础转换:strconv.Atoi
- 功能:将字符串转为 int 类型,是 ParseInt(s, 10, 0) 的简化版(默认十进制,返回 int)。
- 示例(含错误处理):
func main() {
// 合法格式
str1 := "1234"
num1, err := strconv.Atoi(str1)
if err != nil {
fmt.Printf("转换失败:%v
", err)
} else {
fmt.Printf("类型:%T,值:%d
", num1, num1) // 类型:int,值:1234
}
// 非法格式(字母+数字)
str2 := "12a3"
num2, err := strconv.Atoi(str2)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.Atoi: parsing "12a3": invalid syntax
}
// 超出范围(假设系统int为32位,最大值2147483647)
str3 := "2147483648"
num3, err := strconv.Atoi(str3)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.Atoi: parsing "2147483648": value out of range
}
}
灵活转换:strconv.ParseInt
功能:将字符串转为 int64 类型,支持指定进制(0 表明自动识别十进制 / 八进制 / 十六进制)和位数(如 32 表明转为 32 位整型)。
示例(多场景转换):
func main() {
// 1. 指定十进制,返回int64
str1 := "-123456"
num1, err := strconv.ParseInt(str1, 10, 64)
if err == nil {
fmt.Printf("十进制转换:%T,值:%d
", num1, num1) // 十进制转换:int64,值:-123456
}
// 2. 自动识别进制(0开头为八进制,0x开头为十六进制)
str2 := "0144" // 八进制(对应十进制100)
num2, _ := strconv.ParseInt(str2, 0, 64)
fmt.Println("八进制自动识别:", num2) // 八进制自动识别:100
str3 := "0x64" // 十六进制(对应十进制100)
num3, _ := strconv.ParseInt(str3, 0, 64)
fmt.Println("十六进制自动识别:", num3) // 十六进制自动识别:100
// 3. 转为32位整型(超出范围会报错)
str4 := "2147483648" // 超过32位int最大值(2147483647)
num4, err := strconv.ParseInt(str4, 10, 32)
if err != nil {
fmt.Printf("32位转换失败:%v
", err) // 32位转换失败:strconv.ParseInt: parsing "2147483648": value out of range
}
}
2. 字符串与浮点型转换
支持 float32/float64 与字符串的双向转换,float64 是默认高精度类型,转换函数返回值以 float64 为主。
(1)浮点型转字符串:FormatFloat
功能:将 float64 转为字符串,支持指定格式(如科学计数法、保留小数)和精度(小数位数)。
核心参数 fmt 格式选项:
- 'f':固定小数格式(如 123.45);
- 'e'/'E':科学计数法(如 1.23e+02);
- 'g'/'G':自动选择简洁格式(去除末尾无效 0)。
示例:
func main() {
num := 123.456789
// 1. 保留2位小数,固定格式
str1 := strconv.FormatFloat(num, 'f', 2, 64)
fmt.Println("保留2位小数:", str1) // 保留2位小数:123.46(四舍五入)
// 2. 科学计数法,保留3位小数
str2 := strconv.FormatFloat(num, 'e', 3, 64)
fmt.Println("科学计数法:", str2) // 科学计数法:1.235e+02
// 3. 自动简洁格式(去除末尾无效0)
str3 := strconv.FormatFloat(123.4500, 'g', -1, 64)
fmt.Println("简洁格式:", str3) // 简洁格式:123.45
// 4. 整数浮点型转字符串(避免科学计数法)
str4 := strconv.FormatFloat(100.0, 'f', 0, 64)
fmt.Println("整数浮点型:", str4) // 整数浮点型:100
}
(2)字符串转浮点型:ParseFloat
功能:将字符串转为 float64 类型,支持指定精度(32 表明转为 float32,64 表明转为 float64)。
示例(含错误处理):
func main() {
// 合法格式
str1 := "123.456"
num1, err := strconv.ParseFloat(str1, 64)
if err == nil {
fmt.Printf("类型:%T,值:%.3f
", num1, num1) // 类型:float64,值:123.456
}
// 科学计数法格式
str2 := "1.23e+03"
num2, _ := strconv.ParseFloat(str2, 64)
fmt.Println("科学计数法转换:", num2) // 科学计数法转换:1230
// 非法格式(字母)
str3 := "123.45a"
num3, err := strconv.ParseFloat(str3, 64)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.ParseFloat: parsing "123.45a": invalid syntax
}
}
3. 字符串与布尔型转换
布尔型与字符串的转换规则固定,仅支持特定字符串格式。
(1)布尔型转字符串:FormatBool
功能:将 bool 类型转为字符串,true 转 “true”,false 转 “false”,无其他格式。
func main() {
b1 := true
b2 := false
str1 := strconv.FormatBool(b1)
str2 := strconv.FormatBool(b2)
fmt.Println(str1) // true
fmt.Println(str2) // false
}
(2)字符串转布尔型:ParseBool
功能:将字符串转为 bool 类型,仅支持 “true”(不区分大小写?不,严格区分)、”false”、”1″、”0” 四种合法格式,其他格式返回错误。
注意:字符串严格区分大小写,”True”/”TRUE” 均为非法格式。
示例:
func main() {
// 合法格式
str1 := "true"
b1, _ := strconv.ParseBool(str1)
fmt.Println(b1) // true
str2 := "0"
b2, _ := strconv.ParseBool(str2)
fmt.Println(b2) // false
// 非法格式(大写True)
str3 := "True"
b3, err := strconv.ParseBool(str3)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.ParseBool: parsing "True": invalid syntax
}
// 非法格式(其他字符串)
str4 := "yes"
b4, err := strconv.ParseBool(str4)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.ParseBool: parsing "yes": invalid syntax
}
}
4. 其他实用功能
(1)判断字符串是否为数字:IsDigit
功能:判断字符串中的字符是否为十进制数字(0-9),返回 bool 切片(每个字符对应一个结果)。
示例:
func main() {
str := "123abc456"
digits := strconv.IsDigit(str)
for i, c := range str {
fmt.Printf("字符 '%c':%v
", c, digits[i])
}
// 输出:
// 字符 '1':true
// 字符 '2':true
// 字符 '3':true
// 字符 'a':false
// 字符 'b':false
// 字符 'c':false
// 字符 '4':true
// 字符 '5':true
// 字符 '6':true
}
(2)字符串转无符号整型:ParseUint
功能:将字符串转为 uint64 类型,支持指定进制和位数,适用于无符号整数场景(如 ID、序号)。
示例:
func main() {
str := "4294967295" // uint32最大值
num, err := strconv.ParseUint(str, 10, 32)
if err == nil {
fmt.Printf("类型:%T,值:%d
", num, num) // 类型:uint64,值:4294967295
}
// 负数转无符号整型(报错)
str2 := "-100"
num2, err := strconv.ParseUint(str2, 10, 64)
if err != nil {
fmt.Printf("转换失败:%v
", err) // 转换失败:strconv.ParseUint: parsing "-100": invalid syntax
}
}
四、实战注意事项
- 错误必须处理:字符串转基本类型时,格式错误、范围溢出都会返回错误,忽略错误会导致程序崩溃,务必用 if err != nil 处理;
- 整型范围适配:不同系统 int 位数可能不同(32 位 / 64 位),跨平台开发时提议用 ParseInt/FormatInt 指定 int64 类型,避免范围溢出;
- 浮点型精度问题:浮点型本身存在精度误差(如 0.1 + 0.2 ≈ 0.30000000000000004),转换时需注意精度控制,避免直接用 == 比较转换结果;
- 进制识别规则:ParseInt 中 base=0 时,0 开头的字符串会被识别为八进制,0x 开头会被识别为十六进制,需注意格式规范;
- 布尔型严格匹配:ParseBool 仅支持 “true”/”false”/”1″/”0” 四种小写字符串,其他格式(如 “True”/”yes”)均报错。
五、实战小案例:类型转换工具
功能:实现 “字符串转整型 / 浮点型 / 布尔型” 的通用转换函数,包含格式校验和错误提示:
package main
import (
"fmt"
"strconv"
)
// 字符串转整型(默认十进制)
func strToInt(s string) (int, error) {
return strconv.Atoi(s)
}
// 字符串转浮点型(默认64位精度)
func strToFloat(s string) (float64, error) {
return strconv.ParseFloat(s, 64)
}
// 字符串转布尔型
func strToBool(s string) (bool, error) {
return strconv.ParseBool(s)
}
func main() {
// 测试数据
testCases := []struct {
str string
typ string // int/float/bool
}{
{"1234", "int"},
{"123.45", "float"},
{"true", "bool"},
{"abc", "int"},
{"12a3", "float"},
{"Yes", "bool"},
}
// 批量转换测试
for _, tc := range testCases {
fmt.Printf("测试:%s -> %s
", tc.str, tc.typ)
switch tc.typ {
case "int":
num, err := strToInt(tc.str)
if err != nil {
fmt.Printf(" 失败:%v
", err)
} else {
fmt.Printf(" 成功:%d
", num)
}
case "float":
num, err := strToFloat(tc.str)
if err != nil {
fmt.Printf(" 失败:%v
", err)
} else {
fmt.Printf(" 成功:%.2f
", num)
}
case "bool":
b, err := strToBool(tc.str)
if err != nil {
fmt.Printf(" 失败:%v
", err)
} else {
fmt.Printf(" 成功:%v
", b)
}
}
}
}
实战练习
- 编写命令行计算器(支持加减乘除)
- 实现一个简单的文本文件读写工具(如批量替换文本内容)
命令行计算器(Go 实现,支持加减乘除)
一、功能说明
- 支持从命令行输入两个数字和运算符(如 go run calc.go 10 + 20)
- 支持 +(加)、-(减)、*(乘)、/(除)四种运算
- 包含完整错误处理:参数数量错误、运算符非法、除数为 0、类型转换失败等
- 支持浮点型运算(如 1.5 * 2.4)
二、完整代码(calc.go)
package main
import (
"errors"
"fmt"
"os"
"strconv"
)
// 运算核心函数:接收两个浮点数和运算符,返回结果和错误
func calculate(num1, num2 float64, op string) (float64, error) {
switch op {
case "+":
return num1 + num2, nil
case "-":
return num1 - num2, nil
case "*":
return num1 * num2, nil
case "/":
// 处理除数为0的错误
if num2 == 0 {
return 0, errors.New("除数不能为0")
}
return num1 / num2, nil
default:
// 处理非法运算符
return 0, errors.New("非法运算符,仅支持 +、-、*、/")
}
}
func main() {
// 1. 校验命令行参数数量(程序名+数字1+运算符+数字2,共4个参数)
args := os.Args
if len(args) != 4 {
fmt.Println("参数格式错误!正确用法:")
fmt.Println(" go run calc.go 数字1 运算符 数字2")
fmt.Println(" 示例:go run calc.go 10 + 20 或 go run calc.go 3.6 / 1.2")
os.Exit(1) // 退出程序,状态码1表明错误
}
// 2. 解析参数(字符串转浮点型)
num1Str := args[1]
op := args[2]
num2Str := args[3]
// 字符串转浮点型,处理类型错误(如输入"abc")
num1, err := strconv.ParseFloat(num1Str, 64)
if err != nil {
fmt.Printf("错误:第一个参数「%s」不是有效的数字
", num1Str)
os.Exit(1)
}
num2, err := strconv.ParseFloat(num2Str, 64)
if err != nil {
fmt.Printf("错误:第三个参数「%s」不是有效的数字
", num2Str)
os.Exit(1)
}
// 3. 执行运算
result, err := calculate(num1, num2, op)
if err != nil {
fmt.Printf("运算错误:%v
", err)
os.Exit(1)
}
// 4. 输出结果(保留2位小数,提升可读性)
fmt.Printf("运算结果:%.2f %s %.2f = %.2f
", num1, op, num2, result)
}
运行示例,命令行执行
go run calc.go 15.5 + 24.5
核心知识点解析
- 命令行参数读取:os.Args 是字符串切片,存储命令行输入的所有参数,os.Args[0] 为程序名,后续为自定义参数。
- 类型转换:使用 strconv.ParseFloat 将字符串参数转为浮点型,适配整数和小数运算。
- 错误处理:通过 if err != nil 捕获参数错误、运算错误等,并用 os.Exit(1) 终止程序并提示错误。
- 函数封装:将运算逻辑封装为 calculate 函数,提高代码复用性和可读性。
简单文本文件读写工具(支持批量替换)
一、功能说明
- 核心功能:读取指定文本文件内容、批量替换目标字符串、将修改后内容写入新文件(或覆盖原文件)
- 额外特性:支持自定义输入文件路径、输出文件路径、待替换字符串和目标字符串,含完整错误处理(文件不存在、权限不足等)
- 适配场景:日志文件内容替换、配置文件批量修改、文本格式统一等
二、完整代码(file_replace_tool.go)
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
// readFile 读取文件内容,返回每行内容组成的切片和错误信息
func readFile(filePath string) ([]string, error) {
// 打开文件(只读模式)
file, err := os.Open(filePath)
if err != nil {
// 封装错误信息,明确是读取阶段出错
return nil, fmt.Errorf("读取文件失败:%w", err)
}
defer file.Close() // 延迟关闭文件,确保资源释放
var lines []string
scanner := bufio.NewScanner(file) // 创建文件扫描器,按行读取
// 循环读取每行内容
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
// 检查扫描过程中是否出现错误(如文件损坏)
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("扫描文件内容失败:%w", err)
}
return lines, nil
}
// replaceContent 批量替换内容,接收原内容切片、待替换字符串、目标字符串,返回替换后切片
func replaceContent(lines []string, oldStr, newStr string) []string {
var replacedLines []string
for _, line := range lines {
// 替换每行中的目标字符串(全局替换,支持一行多个匹配)
replacedLine := strings.ReplaceAll(line, oldStr, newStr)
replacedLines = append(replacedLines, replacedLine)
}
return replacedLines
}
// writeFile 将内容写入目标文件,支持覆盖已有文件
func writeFile(filePath string, lines []string) error {
// 打开文件:不存在则创建,存在则覆盖(O_TRUNC清空),只写模式
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("创建/打开输出文件失败:%w", err)
}
defer file.Close()
writer := bufio.NewWriter(file) // 创建带缓冲的写入器,提升效率
for _, line := range lines {
// 写入每行内容并添加换行符(保持原文件换行格式)
_, err := writer.WriteString(line + "
")
if err != nil {
return fmt.Errorf("写入内容失败:%w", err)
}
}
// 刷新缓冲区,确保所有内容写入文件(缓冲写入必须调用)
if err := writer.Flush(); err != nil {
return fmt.Errorf("刷新写入缓冲区失败:%w", err)
}
return nil
}
// getInput 读取用户控制台输入,接收提示信息,返回输入内容
func getInput(prompt string) string {
fmt.Print(prompt)
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
return strings.TrimSpace(scanner.Text()) // 去除输入前后的空格和换行
}
func main() {
fmt.Println("===== 文本文件批量替换工具 =====")
fmt.Println("说明:支持所有文本格式(.txt/.log/.conf等),替换为全局匹配")
fmt.Println("-------------------------------")
// 1. 读取用户输入的关键参数
inputPath := getInput("请输入待处理文件路径(如:D:\test\old.txt 或 ./old.txt):")
outputPath := getInput("请输入输出文件路径(如:D:\test\new.txt 或 ./new.txt):")
oldStr := getInput("请输入需要替换的字符串:")
newStr := getInput("请输入替换后的字符串:")
// 2. 校验必要参数(避免空输入导致无效替换)
if inputPath == "" || outputPath == "" || oldStr == "" {
fmt.Println("错误:文件路径和待替换字符串不能为空!")
os.Exit(1)
}
fmt.Println("-------------------------------")
fmt.Printf("正在读取文件:%s
", inputPath)
// 3. 读取原文件内容
originalLines, err := readFile(inputPath)
if err != nil {
fmt.Printf("读取阶段错误:%v
", err)
os.Exit(1)
}
// 4. 执行批量替换
fmt.Printf("正在替换字符串:「%s」→「%s」
", oldStr, newStr)
replacedLines := replaceContent(originalLines, oldStr, newStr)
// 5. 写入替换后的内容到目标文件
fmt.Printf("正在写入文件:%s
", outputPath)
err = writeFile(outputPath, replacedLines)
if err != nil {
fmt.Printf("写入阶段错误:%v
", err)
os.Exit(1)
}
// 6. 统计替换结果(可选增强功能)
replaceCount := 0
for _, line := range originalLines {
// 统计每行的替换次数并累加
lineCount := strings.Count(line, oldStr)
replaceCount += lineCount
}
fmt.Println("-------------------------------")
fmt.Printf("操作完成!共替换 %d 处匹配内容
", replaceCount)
fmt.Printf("替换后文件已保存至:%s
", outputPath)
}
运行示例:
===== 文本文件批量替换工具 =====
说明:支持所有文本格式(.txt/.log/.conf等),替换为全局匹配
-------------------------------
请输入待处理文件路径(如:D: estold.txt 或 ./old.txt):.demo.txt
请输入输出文件路径(如:D: est
ew.txt 或 ./new.txt):.demo2.txt
请输入需要替换的字符串:内容
请输入替换后的字符串:测试
-------------------------------
正在读取文件:.demo.txt
正在替换字符串:「内容」→「测试」
正在写入文件:.demo2.txt
-------------------------------
操作完成!共替换 2 处匹配内容
替换后文件已保存至:.demo2.txt
关键知识点解析
- 文件读写核心:读取:使用 bufio.Scanner 按行读取,避免一次性读取大文件导致内存溢出写入:使用 bufio.Writer 带缓冲写入,提升大文件写入效率,必须调用 Flush() 确保内容写入
- 字符串替换:strings.ReplaceAll 实现全局替换,区别于 strings.Replace(需指定替换次数)
- 错误处理:使用 fmt.Errorf(“描述:%w”, err) 封装错误链,明确错误发生阶段,便于排查
- 用户交互:bufio.Scanner 读取控制台输入,strings.TrimSpace 处理输入冗余空格
- 路径兼容:支持 Windows 绝对路径(D: estfile.txt)和相对路径(./file.txt)
五、常见问题解决
- “读取文件失败:open xxx: The system cannot find the file specified.”
- → 缘由:输入的文件路径错误
- → 解决:检查路径是否正确,绝对路径需带盘符(如 D:),相对路径确保文件在当前运行目录
- “创建 / 打开输出文件失败:open xxx: Access is denied.”
- → 缘由:输出路径无写入权限(如系统目录)
- → 解决:更换输出路径到用户目录(如 C:Users你的用户名Desktop),或右键以管理员身份运行工具
- 替换后文件内容为空
- → 缘由:待替换文件本身为空,或输入的待替换字符串在文件中无匹配
- → 解决:检查原文件内容,确认待替换字符串与文件中的字符完全一致(区分大小写)
- 大文件处理缓慢
- → 优化:当前代码已用缓冲读写,若处理 GB 级文件,可修改 scanner.Buffer 增大缓冲区:
// 在 readFile 函数中创建 scanner 后添加
buf := make([]byte, 1024*1024) // 1MB 缓冲区
scanner.Buffer(buf, bufio.MaxScanTokenSize)