《GO 语言工程实践作业报告:实现思路、代码以及路径记录》
一、项目背景
本次工程实践作业旨在开发一个简单的图书管理系统,实现对图书的添加、查询、修改和删除功能。该系统需要能够存储图书的基本信息,如书名、作者、出版年份等,并提供方便的操作接口,以便管理员或用户对图书信息进行管理和查询。通过这个项目的实践,深入理解和掌握 Go 语言在实际工程中的应用,包括数据结构设计、函数编写、模块组织以及错误处理等方面的知识和技能。
二、实现思路
(一)数据结构设计
首先,确定图书信息的数据结构。使用一个结构体来表示一本图书,包含书名(title)、作者(author)、出版年份(publicationYear)等字段。
type Book struct { Title string Author string PublicationYear int }
然后,需要一个数据存储结构来保存所有的图书信息。考虑到方便查询、添加、修改和删除操作,选择使用切片来存储图书数据。
var books []Book
(二)功能模块划分
1. 添加图书功能:编写一个函数 AddBook,接收一本图书的信息作为参数,将其添加到 books 切片中。在添加之前,需要进行一些基本的验证,如书名和作者不能为空等。
func AddBook(b Book) error { if b.Title == "" || b.Author == "" { return errors.New("书名和作者不能为空") } books = append(books, b) return nil }
2. 查询图书功能:实现 FindBookByTitle 函数,根据书名查询图书。遍历 books 切片,找到匹配书名的图书并返回。
func FindBookByTitle(title string) (*Book, error) { for _, book := range books { if book.Title == title { return &book, nil } } return nil, errors.New("未找到指定书名的图书") }
3. 修改图书功能:ModifyBook 函数用于修改指定图书的信息。先根据书名找到图书,然后更新其相关信息。
func ModifyBook(title string, newBook Book) error { for i, book := range books { if book.Title == title { books[i] = newBook return nil } } return errors.New("未找到指定书名的图书") }
4. 删除图书功能:DeleteBook 函数根据书名删除图书。找到匹配的图书后,从 books 切片中移除。
func DeleteBook(title string) error { for i, book := range books { if book.Title == title { books = append(books[:i], books[i+1:]...) return nil } } return errors.New("未找到指定书名的图书") }
三、代码展示
(一)完整代码
package main
import ( "errors" "fmt" )
type Book struct { Title string Author string PublicationYear int }
var books []Book
func AddBook(b Book) error { if b.Title == "" || b.Author == "" { return errors.New("书名和作者不能为空") } books = append(books, b) return nil }
func FindBookByTitle(title string) (*Book, error) { for _, book := range books { if book.Title == title { return &book, nil } } return nil, errors.New("未找到指定书名的图书") }
func ModifyBook(title string, newBook Book) error { for i, book := range books { if book.Title == title { books[i] = newBook return nil } } return errors.New("未找到指定书名的图书") }
func DeleteBook(title string) error { for i, book := range books { if book.Title == title { books = append(books[:i], books[i+1:]...) return nil } } return errors.New("未找到指定书名的图书") }
func main() { // 添加图书 book1 := Book{Title: "Go 语言编程", Author: "张三", PublicationYear: 2020} err := AddBook(book1) if err!= nil { fmt.Println(err) }
// 查询图书
foundBook, err := FindBookByTitle("Go 语言编程")
if err!= nil {
fmt.Println(err)
} else {
fmt.Printf("找到图书: %s, 作者: %s, 出版年份: %d\n", foundBook.Title, foundBook.Author, foundBook.PublicationYear)
}
// 修改图书
newBook := Book{Title: "Go 语言编程", Author: "李四", PublicationYear: 2021}
err = ModifyBook("Go 语言编程", newBook)
if err!= nil {
fmt.Println(err)
}
// 删除图书
err = DeleteBook("Go 语言编程")
if err!= nil {
fmt.Println(err)
}
// 再次查询图书,验证删除操作
foundBook, err = FindBookByTitle("Go 语言编程")
if err!= nil {
fmt.Println(err)
} else {
fmt.Printf("找到图书: %s, 作者: %s, 出版年份: %d\n", foundBook.Title, foundBook.Author, foundBook.PublicationYear)
}
}
(二)代码注释说明
1. 在 AddBook 函数中,首先检查传入的图书结构体的书名和作者是否为空,如果为空则返回错误。然后将图书添加到 books 切片中。 2. FindBookByTitle 函数遍历 books 切片,逐个比较书名,如果找到匹配的则返回该书的指针和 nil 错误值,否则返回 nil 和表示未找到的错误信息。 3. ModifyBook 函数同样遍历 books 切片,找到匹配书名的图书后,更新其信息为传入的 newBook 结构体中的信息。 4. DeleteBook 函数在找到匹配书名的图书后,使用切片的操作将该书从 books 切片中删除。
四、路径记录
(一)初始开发阶段
1. 首先确定了项目的需求,即实现图书管理系统的基本功能。然后设计了数据结构,选择了结构体和切片来表示和存储图书信息。 2. 开始编写各个功能函数,如 AddBook 函数在编写时,最初没有考虑到书名和作者为空的情况,导致添加图书时可能出现数据不完整的问题。在测试过程中发现了这个问题,于是添加了错误处理逻辑,对书名和作者进行验证。 3. 在实现 FindBookByTitle 函数时,最初的遍历方式比较简单,没有考虑到效率问题。后来考虑到可能存在大量图书的情况,优化了遍历算法,一旦找到匹配的图书就立即返回,减少不必要的遍历。
(二)功能完善与测试阶段
1. 完成了基本功能函数的编写后,进行集成测试。在测试 AddBook 和 FindBookByTitle 函数的组合使用时,发现添加的图书在查询时有时会出现找不到的情况。经过排查,发现是因为在 AddBook 函数中对 books 切片进行添加操作时,可能存在并发安全问题(虽然本项目未涉及并发操作,但这种潜在问题需要注意)。于是考虑在实际的多线程环境下,可能需要对 books 切片的操作进行加锁处理,但本项目暂未深入处理。 2. 在测试 ModifyBook 函数时,发现修改后的图书信息没有正确更新。检查代码后发现是在更新切片中的图书信息时,索引计算错误。修改了索引计算方式后,功能正常。 3. 测试 DeleteBook 函数时,发现删除操作有时会导致切片索引越界错误。这是因为在删除元素后,切片的长度和索引发生了变化,而后续的遍历没有正确处理。通过调整遍历的终止条件,解决了这个问题。
(三)代码优化与总结阶段
1. 对整个代码的结构进行了梳理,发现各个功能函数都直接操作全局的 books 切片,不利于代码的维护和扩展。考虑将对 books 切片的操作封装到一个独立的模块中,对外提供统一的接口,但由于时间关系,本项目暂未进行此优化。 2. 对代码中的错误处理进行了统一规范,确保所有的错误信息都能够清晰地传达给调用者,方便进行错误排查和处理。 3. 总结整个项目的开发过程,记录下遇到的问题、解决方案以及代码的修改历程,以便后续回顾和总结经验教训,同时也为进一步优化和扩展项目提供参考。
五、总结
通过本次图书管理系统的工程实践,深入学习了 Go 语言在实际项目中的应用。在数据结构设计方面,根据项目需求合理选择了结构体和切片来组织数据。在功能模块划分上,将图书管理的各个操作分别封装成独立的函数,提高了代码的可读性和可维护性。在开发过程中,遇到了各种问题,如数据验证、遍历算法优化、切片操作错误等,通过不断地调试和修改代码,最终解决了这些问题,使项目能够正常运行。同时,也意识到代码在结构设计、并发处理等方面还存在可以优化的空间,为今后的学习和实践提供了方向。通过这次实践,不仅提高了 Go 语言编程能力,还培养了良好的编程习惯和问题解决能力,为今后从事更复杂的软件开发项目奠定了基础。