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)普通输出:快速打印

函数

功能说明

示例

输出结果

Print

打印数据,不自动换行,数据间无分隔符

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
}

四、实战注意事项

  1. 地址传递:Scan 系列函数必须传入变量地址(&变量名),否则无法修改变量值(Go 是值传递,不传地址仅操作副本)。
  2. 格式化占位符匹配:Printf 的占位符类型必须与传入参数类型一致(如 %d 对应 int,不能传字符串),否则会输出错误值。
  3. 浮点数精度控制:%f 可通过 %.nf 控制小数位数(n 为位数),如 %.2f 保留 2 位小数。
  4. 标准库特性:fmt 是标准库,无需 go get 安装,直接导入即可;升级 Go 版本时,fmt 包的 API 基本保持兼容,稳定性极高。

os 包:简单文件操作(创建、读取、删除文件)详细讲解

一、核心定位

os 是 Go 标准库中用于 操作系统交互 的核心包,文件操作是其最常用的功能之一,支持创建、读取、删除、重命名等基础文件操作,无需额外依赖,直接导入即可使用。

二、关键前置概念

  1. 文件路径:Windows 系统支持两种格式(C: estfile.txt 或 /test/file.txt,Go 可兼容处理);
  2. 文件权限:Windows 下主要依赖系统权限控制,Go 中创建文件时指定的权限参数(如 0644)会自动适配系统规则;
  3. 错误处理: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)
}

四、实战注意事项

  1. 资源释放:所有通过 os.Open/os.Create/os.OpenFile 打开的文件,必须通过 defer file.Close() 延迟关闭,避免资源泄漏;
  2. 路径处理:Windows 下路径中的反斜杠 需转义(写成 \),或直接使用正斜杠 /(Go 自动兼容);
  3. 大文件处理:避免用 os.ReadFile 读取超大文件(如几十 GB 的日志),应使用 os.Open + 循环读取 分块处理;
  4. 权限问题:若操作系统目录(如 C:Windows),需以 管理员身份 运行程序,否则会返回权限不足错误;
  5. 错误细分:通过 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 标准库中用于 字符串与基本数据类型(整型、浮点型、布尔型等)相互转换 的核心包,解决了不同类型数据间的格式适配问题,是开发中高频使用的工具类包,无需额外依赖,直接导入即可使用。

二、关键前置概念

  1. 转换方向:分为 “基本类型转字符串” 和 “字符串转基本类型” 两类,需根据场景选择对应函数;
  2. 错误处理:字符串转基本类型时,若字符串格式不匹配(如 “abc” 转整型)会返回错误,必须通过 if err != nil 处理;
  3. 进制与精度:整型转字符串支持指定进制(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
    }
}

四、实战注意事项

  1. 错误必须处理:字符串转基本类型时,格式错误、范围溢出都会返回错误,忽略错误会导致程序崩溃,务必用 if err != nil 处理;
  2. 整型范围适配:不同系统 int 位数可能不同(32 位 / 64 位),跨平台开发时提议用 ParseInt/FormatInt 指定 int64 类型,避免范围溢出;
  3. 浮点型精度问题:浮点型本身存在精度误差(如 0.1 + 0.2 ≈ 0.30000000000000004),转换时需注意精度控制,避免直接用 == 比较转换结果;
  4. 进制识别规则:ParseInt 中 base=0 时,0 开头的字符串会被识别为八进制,0x 开头会被识别为十六进制,需注意格式规范;
  5. 布尔型严格匹配: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 实现,支持加减乘除)

一、功能说明

  1. 支持从命令行输入两个数字和运算符(如 go run calc.go 10 + 20)
  2. 支持 +(加)、-(减)、*(乘)、/(除)四种运算
  3. 包含完整错误处理:参数数量错误、运算符非法、除数为 0、类型转换失败等
  4. 支持浮点型运算(如 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

核心知识点解析

  1. 命令行参数读取:os.Args 是字符串切片,存储命令行输入的所有参数,os.Args[0] 为程序名,后续为自定义参数。
  2. 类型转换:使用 strconv.ParseFloat 将字符串参数转为浮点型,适配整数和小数运算。
  3. 错误处理:通过 if err != nil 捕获参数错误、运算错误等,并用 os.Exit(1) 终止程序并提示错误。
  4. 函数封装:将运算逻辑封装为 calculate 函数,提高代码复用性和可读性。

简单文本文件读写工具(支持批量替换)

一、功能说明

  1. 核心功能:读取指定文本文件内容、批量替换目标字符串、将修改后内容写入新文件(或覆盖原文件)
  2. 额外特性:支持自定义输入文件路径、输出文件路径、待替换字符串和目标字符串,含完整错误处理(文件不存在、权限不足等)
  3. 适配场景:日志文件内容替换、配置文件批量修改、文本格式统一等

二、完整代码(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

关键知识点解析

  1. 文件读写核心:读取:使用 bufio.Scanner 按行读取,避免一次性读取大文件导致内存溢出写入:使用 bufio.Writer 带缓冲写入,提升大文件写入效率,必须调用 Flush() 确保内容写入
  2. 字符串替换:strings.ReplaceAll 实现全局替换,区别于 strings.Replace(需指定替换次数)
  3. 错误处理:使用 fmt.Errorf(“描述:%w”, err) 封装错误链,明确错误发生阶段,便于排查
  4. 用户交互:bufio.Scanner 读取控制台输入,strings.TrimSpace 处理输入冗余空格
  5. 路径兼容:支持 Windows 绝对路径(D: estfile.txt)和相对路径(./file.txt)

五、常见问题解决

  1. “读取文件失败:open xxx: The system cannot find the file specified.”
  2. → 缘由:输入的文件路径错误
  3. → 解决:检查路径是否正确,绝对路径需带盘符(如 D:),相对路径确保文件在当前运行目录
  4. “创建 / 打开输出文件失败:open xxx: Access is denied.”
  5. → 缘由:输出路径无写入权限(如系统目录)
  6. → 解决:更换输出路径到用户目录(如 C:Users你的用户名Desktop),或右键以管理员身份运行工具
  7. 替换后文件内容为空
  8. → 缘由:待替换文件本身为空,或输入的待替换字符串在文件中无匹配
  9. → 解决:检查原文件内容,确认待替换字符串与文件中的字符完全一致(区分大小写)
  10. 大文件处理缓慢
  11. → 优化:当前代码已用缓冲读写,若处理 GB 级文件,可修改 scanner.Buffer 增大缓冲区:
// 在 readFile 函数中创建 scanner 后添加
buf := make([]byte, 1024*1024) // 1MB 缓冲区
scanner.Buffer(buf, bufio.MaxScanTokenSize)
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...