当前位置: 首页 > news >正文

go语言项目--实例化(图书管理)--001

案例1:图书管理系统golang

一、项目概述

项目名称:图书管理系统

当前版本:v1.0 - 图书管理系统golang

业务功能:交互式命令行录入图书信息,保存到books.txt

学习目标

  • Go基础语法(变量、常量、类型)

  • 流程控制(if/else、for循环、break)

  • 函数定义与多返回值

  • 错误处理(error接口)

  • 文件操作(os.Create、bufio.Writer)

  • 字符串处理(strings.TrimSpace、strconv.ParseFloat)

运行方式go run main.go

二、完整代码

文件路径case1/main.go

go

复制

下载

// ============================================================ // 图书管理系统 v1.0 - 图书录入器 // 功能:交互式命令行录入图书信息,保存到 books.txt // 学习目标:基础语法、流程控制、函数、错误处理、文件操作 // 运行方式:go run main.go // ============================================================ package main import ( "bufio" "fmt" "os" "strconv" "strings" ) // ============================================================ // 常量定义 // ============================================================ const ( dataFile = "books.txt" // 数据文件名 exitCmd = "quit" // 退出命令 ) // ============================================================ // 主函数 - 程序入口 // ============================================================ func main() { printWelcome() // 打开文件(追加模式) file, err := os.OpenFile(dataFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { fmt.Printf("❌ 打开文件失败: %v\n", err) return } defer file.Close() writer := bufio.NewWriter(file) defer writer.Flush() scanner := bufio.NewScanner(os.Stdin) count := 0 // 主循环 for { fmt.Print("\n📖 请输入(书名,作者,价格),输入 quit 退出: ") scanner.Scan() input := strings.TrimSpace(scanner.Text()) if input == exitCmd { fmt.Printf("\n✅ 共录入 %d 本图书,已保存到 %s\n", count, dataFile) break } // 解析输入 title, author, priceStr, err := parseInput(input) if err != nil { fmt.Printf("❌ 格式错误: %v(正确格式:书名,作者,价格)\n", err) continue } // 校验 if err := validateTitle(title); err != nil { fmt.Printf("❌ %v\n", err) continue } if err := validateAuthor(author); err != nil { fmt.Printf("❌ %v\n", err) continue } price, err := parsePrice(priceStr) if err != nil { fmt.Printf("❌ %v\n", err) continue } // 写入文件 line := fmt.Sprintf("%s,%s,%.2f\n", title, author, price) if _, err := writer.WriteString(line); err != nil { fmt.Printf("❌ 写入失败: %v\n", err) continue } writer.Flush() count++ fmt.Printf("✅ 第 %d 本录入成功: %s\n", count, strings.TrimSpace(line)) } } // ============================================================ // 辅助函数 // ============================================================ func printWelcome() { fmt.Println("========================================") fmt.Println(" 📚 图书管理系统 v1.0 - 图书录入器") fmt.Println("========================================") fmt.Printf(" 💡 格式:书名,作者,价格\n") fmt.Printf(" 💡 输入 %s 退出\n", exitCmd) fmt.Printf(" 💡 数据保存到 %s\n", dataFile) fmt.Println("========================================") } // parseInput 按逗号分割输入,返回书名、作者、价格字符串 func parseInput(input string) (title, author, price string, err error) { parts := strings.Split(input, ",") if len(parts) != 3 { return "", "", "", fmt.Errorf("需要3个字段,实际%d个", len(parts)) } return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), strings.TrimSpace(parts[2]), nil } // validateTitle 校验书名不能为空 func validateTitle(title string) error { if title == "" { return fmt.Errorf("书名不能为空") } return nil } // validateAuthor 校验作者不能为空 func validateAuthor(author string) error { if author == "" { return fmt.Errorf("作者不能为空") } return nil } // parsePrice 解析价格,必须为数字且 >= 0 func parsePrice(priceStr string) (float64, error) { price, err := strconv.ParseFloat(priceStr, 64) if err != nil { return 0, fmt.Errorf("价格格式错误") } if price < 0 { return 0, fmt.Errorf("价格不能为负数") } return price, nil } // ============================================================ // 备选交互方式:fmt.Scanln(注释掉,供参考对比) // 优点:写法简洁;缺点:无法处理带空格的输入 // ============================================================ // var title, author, priceStr string // fmt.Print("请输入书名: ") // fmt.Scanln(&title) // fmt.Print("请输入作者: ") // fmt.Scanln(&author) // fmt.Print("请输入价格: ") // fmt.Scanln(&priceStr) // ============================================================ // 本案例知识点: // 变量/常量 | if/for | 函数多返回值 | error处理 | 文件操作 | 字符串处理 // ============================================================

三、测试代码(精简版)

文件路径case1/main_test.go

go

复制

下载

package main import "testing" // 测试价格解析 func TestParsePrice(t *testing.T) { tests := []struct { name string input string want float64 ok bool // true表示期望成功 }{ {"正常价格", "59.00", 59.00, true}, {"整数", "59", 59.00, true}, {"零元", "0", 0, true}, {"负数", "-10", 0, false}, {"非数字", "abc", 0, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := parsePrice(tt.input) if tt.ok && err != nil { t.Errorf("期望成功,但返回错误: %v", err) } if !tt.ok && err == nil { t.Errorf("期望失败,但成功了") } if tt.ok && got != tt.want { t.Errorf("got %f, want %f", got, tt.want) } }) } } // 测试书名校验 func TestValidateTitle(t *testing.T) { err := validateTitle("") if err == nil { t.Error("空书名应该返回错误") } err = validateTitle("Go语言") if err != nil { t.Errorf("正常书名不应该返回错误: %v", err) } } // 测试输入解析 func TestParseInput(t *testing.T) { title, author, price, err := parseInput("Go语言,张三,59.00") if err != nil { t.Errorf("解析失败: %v", err) } if title != "Go语言" || author != "张三" || price != "59.00" { t.Errorf("解析结果不符: %s, %s, %s", title, author, price) } _, _, _, err = parseInput("Go语言,张三") if err == nil { t.Error("字段不足应该返回错误") } } // 运行测试:go test -v // 运行指定测试:go test -v -run TestParsePrice

四、运行指南

bash

复制

下载

# 运行程序 cd case1 go run main.go # 运行测试 go test -v # 测试覆盖率 go test -v -cover

五、交互示例

text

复制

下载

======================================== 📚 图书管理系统 v1.0 - 图书录入器 ======================================== 💡 格式:书名,作者,价格 💡 输入 quit 退出 💡 数据保存到 books.txt ======================================== 📖 请输入(书名,作者,价格),输入 quit 退出: Go语言实战,张三,59.00 ✅ 第 1 本录入成功: Go语言实战,张三,59.00 📖 请输入(书名,作者,价格),输入 quit 退出: ,王五,30 ❌ 书名不能为空 📖 请输入(书名,作者,价格),输入 quit 退出: 测试书,赵六,-10 ❌ 价格不能为负数 📖 请输入(书名,作者,价格),输入 quit 退出: quit ✅ 共录入 1 本图书,已保存到 books.txt

六、案例1 → 案例2 衔接

text

复制

下载

============================================================ 📌 案例1结束,案例2衔接说明 ============================================================ 1. 本案例已学知识点: ✅ 变量/常量、基本类型 ✅ if/else、for循环、break ✅ 函数定义与多返回值 ✅ error错误处理 ✅ 文件操作(os.OpenFile、defer) ✅ 缓冲写入(bufio.Writer) ✅ 字符串处理(TrimSpace、Split) ✅ 类型转换(strconv.ParseFloat) ✅ 单元测试(表驱动测试、t.Run) 2. 案例2将升级: 📄 books.txt → books.json(结构化数据) 📁 单文件 → 多包分层(model/repository/handler) 🔧 仅录入 → 完整CRUD(增删改查) 3. 本案例后续可优化(将在案例2中实现): 🔸 用结构体代替分散的字符串变量 🔸 用JSON替代纯文本,支持结构化存储 🔸 增加查询、更新、删除功能 🔸 增加内存存储,提高操作效率 ============================================================
http://www.jsqmd.com/news/1113171/

相关文章:

  • 中间继电器到底干什么用的?90%的新手没搞懂
  • Java毕业设计实战:Spring Boot+MyBatis-Plus健身房管理系统开发指南
  • 2026 AI编程工具选边站:IDE派与Agent派的温馨拆解
  • 深度解析许可优化策略:让软件授权不再浪费
  • 橡胶垫、密封圈尺寸检测提速方案:一台自动影像测量仪搞定全品类
  • 钱对不上、利润算不准?电商企业多平台对账的深层解法
  • 90天掌握AI智能体开发:从新手到专家的SOP指南
  • 智慧校园运维升级:IoT智能锁身份核验与通断电联动落地实践
  • 腾讯混元3D开源:8G显存跑通AIGC生成可编辑3D模型
  • Java应用性能测试自动化:从JMeter实战到高并发调优
  • 26教资报名照片审核不通过?常见原因与正确照片尺寸全解析
  • 饮用水pH计的技术原理科普
  • AI Agent工作流系统设计与实践指南
  • LINUX高通平台交叉编译地图软件PROJ
  • 多维聚合实战:从OLAP立方体到语义层的全链路解析
  • 二级分销爆单的“财务噩梦”:为什么微商城一卡,老板的钱就被多提现了?
  • IIS短文件名漏洞:原理、检测与彻底修复实战指南
  • Django分页封装
  • 近期零基础量化,工具重点要跟着阶段变
  • 马尔可夫链与HMM工程实战:从状态设计到生产部署
  • 组件类型-Props-Emits-Ref
  • 一次性讲清楚 Node.js 事件循环(Event Loop)
  • Selenium自动化测试与动态网页爬虫实战指南
  • 二十年只为超越,ROG玩家国度与蜘蛛侠共赴英雄新章
  • 搭建微信电商小程序要多少钱:定制和SaaS商城怎么选更适合实体店
  • ThinkPad风扇控制终极指南:TPFanCtrl2实现128级无级调速与智能温控
  • DALL·E Mini本地部署实战:轻量级文本生成图像入门指南
  • CPPM注册职业采购经理怎么报名?报考条件、费用和证书查询一次说清
  • 梯度下降工程实践:从GPU训练到嵌入式微调的全栈调试指南
  • 2025-2026中国高端门窗十大品牌解析:核心实力与行业发展指南