写在最前

x. 示例项目

x. book_management

book_management/

├── main.go # 程序入口

├── book.go # 图书结构和方法

├── user.go # 用户结构和方法

├── library.go # 图书馆管理逻辑

├── storage.go # 数据存储

└── menu.go # 用户界面菜单

book.go - 图书模型

package main

import (
	"fmt"
	"time"
)

// Book 结构体表示一本图书
type Book struct {
	ID        int       // 图书ID
	Title     string    // 书名
	Author    string    // 作者
	ISBN      string    // ISBN号
	Available bool      // 是否可借
	Borrower  string    // 借阅者姓名(如果被借出)
	DueDate   time.Time // 应归还日期
}

// NewBook 创建新图书
func NewBook(id int, title, author, isbn string) *Book {
	return &Book{
		ID:        id,
		Title:     title,
		Author:    author,
		ISBN:      isbn,
		Available: true,
		Borrower:  "",
		DueDate:   time.Time{},
	}
}

// Borrow 借阅图书
func (b *Book) Borrow(borrower string, days int) error {
	if !b.Available {
		return fmt.Errorf("书籍《%s》已被借出", b.Title)
	}

	b.Available = false
	b.Borrower = borrower
	b.DueDate = time.Now().AddDate(0, 0, days)
	return nil
}

// Return 归还图书
func (b *Book) Return() {
	b.Available = true
	b.Borrower = ""
	b.DueDate = time.Time{}
}

// Display 显示图书信息
func (b *Book) Display() {
	status := "可借阅"
	if !b.Available {
		status = fmt.Sprintf("已借出(借阅人:%s,应归还:%s)",
			b.Borrower, b.DueDate.Format("2006-01-02"))
	}

	fmt.Printf("ID: %d | 《%s》- %s | ISBN: %s | 状态: %s\n",
		b.ID, b.Title, b.Author, b.ISBN, status)
}

user.go - 用户模型

package main

import "fmt"

// User 结构体表示系统用户
type User struct {
	ID       int    // 用户ID
	Name     string // 姓名
	Email    string // 邮箱
	Borrowed []int  // 借阅的图书ID列表
}

// NewUser 创建新用户
func NewUser(id int, name, email string) *User {
	return &User{
		ID:       id,
		Name:     name,
		Email:    email,
		Borrowed: make([]int, 0),
	}
}

// BorrowBook 用户借书
func (u *User) BorrowBook(bookID int) {
	u.Borrowed = append(u.Borrowed, bookID)
}

// ReturnBook 用户还书
func (u *User) ReturnBook(bookID int) {
	for i, id := range u.Borrowed {
		if id == bookID {
			u.Borrowed = append(u.Borrowed[:i], u.Borrowed[i+1:]...)
			break
		}
	}
}

// Display 显示用户信息
func (u *User) Display() {
	fmt.Printf("用户ID: %d | 姓名: %s | 邮箱: %s | 借阅数量: %d\n",
		u.ID, u.Name, u.Email, len(u.Borrowed))
}

storage.go - 数据存储

package main

import (
	"encoding/json"
	"os"
	"sync"
)

// Storage 管理数据存储
type Storage struct {
	Books    map[int]*Book // 图书数据
	Users    map[int]*User // 用户数据
	nextBookID int         // 下一个图书ID
	nextUserID int         // 下一个用户ID
	mu       sync.RWMutex  // 读写锁,保证并发安全
}

// NewStorage 创建存储实例
func NewStorage() *Storage {
	return &Storage{
		Books:      make(map[int]*Book),
		Users:      make(map[int]*User),
		nextBookID: 1,
		nextUserID: 1,
	}
}

// SaveToFile 保存数据到文件
func (s *Storage) SaveToFile(filename string) error {
	s.mu.RLock()
	defer s.mu.RUnlock()

	data := struct {
		Books      map[int]*Book `json:"books"`
		Users      map[int]*User `json:"users"`
		NextBookID int           `json:"next_book_id"`
		NextUserID int           `json:"next_user_id"`
	}{
		Books:      s.Books,
		Users:      s.Users,
		NextBookID: s.nextBookID,
		NextUserID: s.nextUserID,
	}

	file, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return err
	}

	return os.WriteFile(filename, file, 0644)
}

// LoadFromFile 从文件加载数据
func (s *Storage) LoadFromFile(filename string) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	file, err := os.ReadFile(filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // 文件不存在时返回nil,使用初始数据
		}
		return err
	}

	var data struct {
		Books      map[int]*Book `json:"books"`
		Users      map[int]*User `json:"users"`
		NextBookID int           `json:"next_book_id"`
		NextUserID int           `json:"next_user_id"`
	}

	if err := json.Unmarshal(file, &data); err != nil {
		return err
	}

	s.Books = data.Books
	s.Users = data.Users
	s.nextBookID = data.NextBookID
	s.nextUserID = data.NextUserID

	return nil
}

// AddBook 添加图书
func (s *Storage) AddBook(title, author, isbn string) *Book {
	s.mu.Lock()
	defer s.mu.Unlock()

	book := NewBook(s.nextBookID, title, author, isbn)
	s.Books[s.nextBookID] = book
	s.nextBookID++

	return book
}

// AddUser 添加用户
func (s *Storage) AddUser(name, email string) *User {
	s.mu.Lock()
	defer s.mu.Unlock()

	user := NewUser(s.nextUserID, name, email)
	s.Users[s.nextUserID] = user
	s.nextUserID++

	return user
}

// GetBook 获取图书
func (s *Storage) GetBook(id int) (*Book, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	book, exists := s.Books[id]
	return book, exists
}

// GetUser 获取用户
func (s *Storage) GetUser(id int) (*User, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	user, exists := s.Users[id]
	return user, exists
}

// GetAllBooks 获取所有图书
func (s *Storage) GetAllBooks() []*Book {
	s.mu.RLock()
	defer s.mu.RUnlock()

	books := make([]*Book, 0, len(s.Books))
	for _, book := range s.Books {
		books = append(books, book)
	}
	return books
}

// GetAllUsers 获取所有用户
func (s *Storage) GetAllUsers() []*User {
	s.mu.RLock()
	defer s.mu.RUnlock()

	users := make([]*User, 0, len(s.Users))
	for _, user := range s.Users {
		users = append(users, user)
	}
	return users
}

library.go - 核心业务逻辑

package main

import (
	"fmt"
	"strings"
)

// Library 图书馆管理系统
type Library struct {
	storage *Storage
}

// NewLibrary 创建图书馆实例
func NewLibrary() *Library {
	library := &Library{
		storage: NewStorage(),
	}

	// 加载已有数据
	if err := library.storage.LoadFromFile("library_data.json"); err != nil {
		fmt.Printf("加载数据失败: %v\n", err)
		fmt.Println("将使用初始空数据")
	}

	return library
}

// AddBook 添加图书
func (l *Library) AddBook(title, author, isbn string) {
	book := l.storage.AddBook(title, author, isbn)
	fmt.Printf("✅ 添加成功!图书ID: %d\n", book.ID)
	l.SaveData()
}

// AddUser 添加用户
func (l *Library) AddUser(name, email string) {
	user := l.storage.AddUser(name, email)
	fmt.Printf("✅ 用户添加成功!用户ID: %d\n", user.ID)
	l.SaveData()
}

// ListBooks 列出所有图书
func (l *Library) ListBooks() {
	books := l.storage.GetAllBooks()

	if len(books) == 0 {
		fmt.Println("📚 图书馆暂无图书")
		return
	}

	fmt.Printf("📚 图书列表(共 %d 本):\n", len(books))
	for _, book := range books {
		book.Display()
	}
}

// ListUsers 列出所有用户
func (l *Library) ListUsers() {
	users := l.storage.GetAllUsers()

	if len(users) == 0 {
		fmt.Println("👤 暂无用户")
		return
	}

	fmt.Printf("👤 用户列表(共 %d 人):\n", len(users))
	for _, user := range users {
		user.Display()
	}
}

// BorrowBook 借阅图书
func (l *Library) BorrowBook(bookID, userID, days int) {
	book, bookExists := l.storage.GetBook(bookID)
	if !bookExists {
		fmt.Printf("❌ 图书ID %d 不存在\n", bookID)
		return
	}

	user, userExists := l.storage.GetUser(userID)
	if !userExists {
		fmt.Printf("❌ 用户ID %d 不存在\n", userID)
		return
	}

	if err := book.Borrow(user.Name, days); err != nil {
		fmt.Printf("❌ 借阅失败: %v\n", err)
		return
	}

	user.BorrowBook(bookID)
	fmt.Println("✅ 借阅成功!")
	l.SaveData()
}

// ReturnBook 归还图书
func (l *Library) ReturnBook(bookID int) {
	book, exists := l.storage.GetBook(bookID)
	if !exists {
		fmt.Printf("❌ 图书ID %d 不存在\n", bookID)
		return
	}

	if book.Available {
		fmt.Println("❌ 这本书没有被借出")
		return
	}

	// 找到借阅者并更新其借阅记录
	for _, user := range l.storage.GetAllUsers() {
		for _, borrowedID := range user.Borrowed {
			if borrowedID == bookID {
				user.ReturnBook(bookID)
				break
			}
		}
	}

	book.Return()
	fmt.Println("✅ 归还成功!")
	l.SaveData()
}

// SearchBooks 搜索图书
func (l *Library) SearchBooks(keyword string) {
	books := l.storage.GetAllBooks()
	results := make([]*Book, 0)

	keyword = strings.ToLower(keyword)

	for _, book := range books {
		if strings.Contains(strings.ToLower(book.Title), keyword) ||
			strings.Contains(strings.ToLower(book.Author), keyword) ||
			strings.Contains(strings.ToLower(book.ISBN), keyword) {
			results = append(results, book)
		}
	}

	if len(results) == 0 {
		fmt.Printf("🔍 未找到包含 \"%s\" 的图书\n", keyword)
		return
	}

	fmt.Printf("🔍 找到 %d 本相关图书:\n", len(results))
	for _, book := range results {
		book.Display()
	}
}

// SaveData 保存数据
func (l *Library) SaveData() {
	if err := l.storage.SaveToFile("library_data.json"); err != nil {
		fmt.Printf("⚠️  保存数据失败: %v\n", err)
	} else {
		fmt.Println("💾 数据已自动保存")
	}
}
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// Menu 管理用户界面
type Menu struct {
	library *Library
	scanner *bufio.Scanner
}

// NewMenu 创建菜单
func NewMenu(library *Library) *Menu {
	return &Menu{
		library: library,
		scanner: bufio.NewScanner(os.Stdin),
	}
}

// Run 运行主菜单
func (m *Menu) Run() {
	for {
		m.showMainMenu()
		choice := m.getInput("请选择操作: ")

		switch choice {
		case "1":
			m.addBook()
		case "2":
			m.library.ListBooks()
		case "3":
			m.addUser()
		case "4":
			m.library.ListUsers()
		case "5":
			m.borrowBook()
		case "6":
			m.returnBook()
		case "7":
			m.searchBooks()
		case "8":
			fmt.Println("谢谢使用!再见!")
			m.library.SaveData()
			return
		default:
			fmt.Println("无效选择,请重新输入")
		}

		fmt.Println()
	}
}

func (m *Menu) showMainMenu() {
	fmt.Println("\n===== 图书管理系统 =====")
	fmt.Println("1. 添加图书")
	fmt.Println("2. 查看所有图书")
	fmt.Println("3. 添加用户")
	fmt.Println("4. 查看所有用户")
	fmt.Println("5. 借阅图书")
	fmt.Println("6. 归还图书")
	fmt.Println("7. 搜索图书")
	fmt.Println("8. 退出系统")
	fmt.Println("======================")
}

func (m *Menu) addBook() {
	fmt.Println("\n--- 添加图书 ---")
	title := m.getInput("书名: ")
	author := m.getInput("作者: ")
	isbn := m.getInput("ISBN: ")

	if title == "" || author == "" {
		fmt.Println("❌ 书名和作者不能为空")
		return
	}

	m.library.AddBook(title, author, isbn)
}

func (m *Menu) addUser() {
	fmt.Println("\n--- 添加用户 ---")
	name := m.getInput("姓名: ")
	email := m.getInput("邮箱: ")

	if name == "" {
		fmt.Println("❌ 姓名不能为空")
		return
	}

	m.library.AddUser(name, email)
}

func (m *Menu) borrowBook() {
	fmt.Println("\n--- 借阅图书 ---")

	bookIDStr := m.getInput("图书ID: ")
	bookID, err := strconv.Atoi(bookIDStr)
	if err != nil {
		fmt.Println("❌ 请输入有效的图书ID(数字)")
		return
	}

	userIDStr := m.getInput("用户ID: ")
	userID, err := strconv.Atoi(userIDStr)
	if err != nil {
		fmt.Println("❌ 请输入有效的用户ID(数字)")
		return
	}

	daysStr := m.getInput("借阅天数: ")
	days, err := strconv.Atoi(daysStr)
	if err != nil || days <= 0 {
		fmt.Println("❌ 请输入有效的借阅天数(正整数)")
		return
	}

	m.library.BorrowBook(bookID, userID, days)
}

func (m *Menu) returnBook() {
	fmt.Println("\n--- 归还图书 ---")
	bookIDStr := m.getInput("图书ID: ")
	bookID, err := strconv.Atoi(bookIDStr)
	if err != nil {
		fmt.Println("❌ 请输入有效的图书ID(数字)")
		return
	}

	m.library.ReturnBook(bookID)
}

func (m *Menu) searchBooks() {
	fmt.Println("\n--- 搜索图书 ---")
	keyword := m.getInput("请输入书名、作者或ISBN关键字: ")

	if keyword == "" {
		fmt.Println("❌ 搜索关键字不能为空")
		return
	}

	m.library.SearchBooks(keyword)
}

func (m *Menu) getInput(prompt string) string {
	fmt.Print(prompt)
	m.scanner.Scan()
	return strings.TrimSpace(m.scanner.Text())
}

main.go - 程序入口

package main

import "fmt"

func main() {
	fmt.Println("📚 欢迎使用图书管理系统")
	fmt.Println("========================")

	// 初始化图书馆系统
	library := NewLibrary()

	// 初始化菜单
	menu := NewMenu(library)

	// 运行系统
	menu.Run()
}

写在最后