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

《Go 简易速速上手小册》第3章:数据结构(2024 最新版)

在这里插入图片描述

文章目录

  • 3.1 数组与切片:Go 语言的动态队伍
    • 3.1.1 基础知识讲解
    • 3.1.2 重点案例:动态成绩单
      • 功能描述
      • 实现代码
      • 扩展功能
    • 3.1.3 拓展案例 1:数据分析
      • 功能描述
      • 实现代码
      • 扩展功能
    • 3.1.4 拓展案例 2:日志过滤器
      • 功能描述
      • 实现代码
      • 扩展功能
  • 3.2 映射(Map):Go 语言的宝藏地图
    • 3.2.1 基础知识讲解
    • 3.2.2 重点案例:投票系统
      • 功能描述
      • 实现代码
      • 扩展功能
    • 3.2.3 拓展案例 1:库存管理
      • 功能描述
      • 实现代码
      • 扩展功能
    • 3.2.4 拓展案例 2:员工目录
      • 功能描述
      • 实现代码
      • 扩展功能
  • 3.3 结构体与方法:Go 语言的构建块
    • 3.3.1 基础知识讲解
    • 3.3.2 重点案例:图书管理系统
      • 功能描述
      • 实现代码
    • 3.3.3 拓展案例 1:员工管理系统
      • 功能描述
      • 实现代码
      • 扩展功能
    • 3.3.4 拓展案例 2:在线商店的购物车
      • 功能描述
      • 实现代码
      • 扩展功能

3.1 数组与切片:Go 语言的动态队伍

在 Go 语言的壮丽世界中,数组和切片是组织和存储数据的强大工具。数组像是一个固定大小的容器,而切片则更加灵活,能够动态地伸缩。让我们深入探究这两种结构,以及它们如何帮助我们在编程冒险中更有效地管理数据。

3.1.1 基础知识讲解

数组(Array)

数组是一种固定长度的数据类型,能够存储一系列相同类型的数据。在 Go 中,数组的长度在声明时就已确定,且不能更改。

var myArray [5]int // 声明一个包含5个整数的数组

数组的索引(即元素的位置)从 0 开始计数。

切片(Slice)

切片是 Go 语言中一个更加灵活的数据结构,它提供了对数组的抽象。切片不需要在声明时指定长度,可以根据需要动态地增长或缩小。

mySlice := []int{1, 2, 3} // 使用切片字面量初始化切片
mySlice = append(mySlice, 4) // 向切片中追加元素

切片的底层实际上是数组,它通过指针、长度和容量来工作。append 函数可以用来增加切片的长度。

3.1.2 重点案例:动态成绩单

在现实世界的应用中,处理成绩单这样的数据是非常常见的任务。让我们进一步扩展动态成绩单的案例,创建一个功能更全面的成绩管理系统。这个系统不仅可以添加和更新学生成绩,还可以删除成绩、计算全班的平均成绩,并列出所有学生的成绩。

功能描述

  1. 添加和更新学生成绩。
  2. 删除学生成绩。
  3. 计算全班的平均成绩。
  4. 列出所有学生的成绩。

实现代码

我们将使用 Go 语言中的切片和映射来实现这个系统:

package mainimport ("fmt"
)// 成绩管理系统结构体
type ScoreManager struct {scores map[string]int
}// 新建成绩管理系统
func NewScoreManager() *ScoreManager {return &ScoreManager{scores: make(map[string]int)}
}// 添加或更新成绩
func (sm *ScoreManager) UpdateScore(name string, score int) {sm.scores[name] = scorefmt.Printf("更新了 %s 的成绩为 %d\n", name, score)
}// 删除成绩
func (sm *ScoreManager) DeleteScore(name string) {_, exists := sm.scores[name]if exists {delete(sm.scores, name)fmt.Printf("删除了 %s 的成绩\n", name)} else {fmt.Printf("%s 的成绩不存在\n", name)}
}// 计算平均成绩
func (sm *ScoreManager) CalculateAverage() float64 {var total intfor _, score := range sm.scores {total += score}return float64(total) / float64(len(sm.scores))
}// 列出所有成绩
func (sm *ScoreManager) ListScores() {fmt.Println("所有学生的成绩:")for name, score := range sm.scores {fmt.Printf("%s: %d\n", name, score)}
}func main() {sm := NewScoreManager()sm.UpdateScore("Alice", 95)sm.UpdateScore("Bob", 82)sm.ListScores()average := sm.CalculateAverage()fmt.Printf("全班平均成绩:%.2f\n", average)sm.DeleteScore("Bob")sm.ListScores()
}

扩展功能

在上述基础功能之外,我们可以进一步扩展这个成绩管理系统,例如添加一个功能来识别和奖励成绩优秀的学生,或者提供一个搜索功能,让用户可以快速查找特定学生的成绩。

通过这个案例的扩展,我们演示了如何使用 Go 语言中的切片和映射来处理和管理复杂的数据。这种类型的系统在现实世界的应用程序开发中非常常见,比如学生信息系统、员工管理系统等。掌握了这些基础知识和技能,你就可以开始构建自己的数据管理应用了。随着你对 Go 语言的深入学习,你将能够开发出更加复杂和功能丰富的系统。

3.1.3 拓展案例 1:数据分析

在数据分析领域,处理和分析数据集是常见的需求。这通常涉及到寻找数据的最大值、最小值、平均值等统计信息。通过这个案例,我们将扩展之前的概念,创建一个更实用的数据分析工具,该工具可以处理一组数据,并提供这些统计信息以及标准偏差,以评估数据的分布情况。

功能描述

  1. 计算数据集的最大值、最小值和平均值。
  2. 计算数据集的标准偏差,以评估数据分布的离散程度。

实现代码

我们将首先定义函数来计算最大值、最小值、平均值,然后扩展功能以包括计算标准偏差:

package mainimport ("fmt""math"
)// calculateStats 计算最大值、最小值和平均值
func calculateStats(data []float64) (min float64, max float64, avg float64) {if len(data) == 0 {return 0, 0, 0}min, max = data[0], data[0]sum := 0.0for _, value := range data {if value < min {min = value}if value > max {max = value}sum += value}avg = sum / float64(len(data))return min, max, avg
}// calculateStdDev 计算标准偏差
func calculateStdDev(data []float64, mean float64) float64 {var variance float64for _, value := range data {variance += math.Pow(value-mean, 2)}variance /= float64(len(data))return math.Sqrt(variance)
}func main() {data := []float64{10, 12, 23, 23, 16, 23, 21, 16}min, max, avg := calculateStats(data)stdDev := calculateStdDev(data, avg)fmt.Printf("数据集: %v\n", data)fmt.Printf("最小值: %.2f\n", min)fmt.Printf("最大值: %.2f\n", max)fmt.Printf("平均值: %.2f\n", avg)fmt.Printf("标准偏差: %.2f\n", stdDev)
}

扩展功能

在上述基础功能之外,我们可以进一步扩展这个数据分析工具,例如添加数据可视化功能,将数据和统计信息以图表的形式展现出来。虽然在 Go 语言标准库中没有直接支持数据可视化的库,但是我们可以利用第三方库如gonum/plot来实现这个功能。

通过这个案例的扩展,我们展示了如何使用 Go 语言进行基本的数据分析操作,包括统计计算和标准偏差的计算。这些技能在数据科学、金融分析、物理研究等多个领域都非常有用。掌握了这些基础后,你就能开始探索更复杂的数据处理和分析任务,为解决实际问题提供强大的工具。

3.1.4 拓展案例 2:日志过滤器

在软件开发和系统管理中,日志文件是宝贵的信息源,它们记录了程序运行时的各种事件。处理和分析这些日志文件,特别是能够从中过滤出错误和警告信息,对于维护和改进系统至关重要。通过这个案例,我们将构建一个更高级的日志过滤器,该过滤器不仅能过滤错误信息,还能分类不同级别的日志,并提供一个摘要报告,概述日志文件中各类消息的数量。

功能描述

  1. 从日志文件中过滤出错误(ERROR)、警告(WARNING)和信息(INFO)级别的日志。
  2. 为每种日志级别计数。
  3. 输出一个摘要报告,显示每种日志级别的总数。

实现代码

首先,我们将定义函数来读取日志文件,并使用 strings 包来检查每行日志的级别。然后,我们将统计每种日志级别的数量,并最终生成一个摘要报告。

package mainimport ("bufio""fmt""os""strings"
)// LogSummary 用于存储日志摘要信息
type LogSummary struct {Info    intWarning intError   int
}// processLogs 处理日志文件,并返回日志摘要
func processLogs(filename string) (LogSummary, error) {file, err := os.Open(filename)if err != nil {return LogSummary{}, err}defer file.Close()var summary LogSummaryscanner := bufio.NewScanner(file)for scanner.Scan() {line := scanner.Text()switch {case strings.Contains(line, "ERROR"):summary.Error++case strings.Contains(line, "WARNING"):summary.Warning++case strings.Contains(line, "INFO"):summary.Info++}}if err := scanner.Err(); err != nil {return LogSummary{}, err}return summary, nil
}func main() {filename := "logs.txt" // 假设这是我们要处理的日志文件summary, err := processLogs(filename)if err != nil {fmt.Println("处理日志时发生错误:", err)return}fmt.Println("日志摘要:")fmt.Printf("信息: %d\n", summary.Info)fmt.Printf("警告: %d\n", summary.Warning)fmt.Printf("错误: %d\n", summary.Error)
}

扩展功能

在上述基础功能之外,我们可以进一步扩展这个日志过滤器,例如:

  • 添加对更多日志级别的支持,如 DEBUG 或 FATAL。
  • 提供选项让用户选择只显示特定级别的日志。
  • 输出日志的详细分析报告,比如显示每种日志级别的百分比。
  • 支持从远程服务器上读取日志文件,增加日志过滤器的应用场景。

通过这个案例的扩展,我们演示了如何使用 Go 语言处理文本文件,并进行基本的文本分析。这种技能在很多领域都非常有用,比如数据分析、系统监控和自动化测试。掌握了这些技能后,你就可以开始构建更复杂的文本处理和分析工具,为日常工作提供强大的支持。

3.2 映射(Map):Go 语言的宝藏地图

Ahoy, 编程海盗们!在 Go 语言的广阔海洋中,映射(Map)是寻宝的关键。映射就像是一张藏宝图,它帮助你快速找到那些被“关键词”标记的宝藏(值)。不管你的宝藏是什么——一串数字、一个字符串,还是一个复杂的结构体,映射都能帮你快速定位。

3.2.1 基础知识讲解

映射的定义和初始化

映射是一种存储键值对的数据结构,每个键映射到一个唯一的值。在 Go 中,使用 map 关键字和 make 函数来定义和初始化映射。

// 定义并初始化一个映射
var myMap map[string]int = make(map[string]int)// 或者更简洁地
myMap := make(map[string]int)// 使用映射字面量初始化映射
treasureMap := map[string]string{"海盗湾": "金币","神秘洞穴": "宝石",
}

映射的操作

映射支持添加、删除、查找和遍历操作。

// 添加或更新
myMap["新的岛屿"] = 100// 删除
delete(myMap, "新的岛屿")// 查找
value, exists := myMap["海盗湾"]// 遍历
for key, value := range treasureMap {fmt.Printf("%s 有 %s\n", key, value)
}

3.2.2 重点案例:投票系统

在一个投票系统中,我们不仅需要统计每个候选人的得票数,而且还可能需要实现更复杂的功能,比如添加新的候选人、撤销投票以及实时更新投票结果的功能。这样的系统在现实世界的应用非常广泛,比如选举投票、在线调查或者社交媒体上的投票活动。

功能描述

  1. 统计每个候选人的得票数。
  2. 添加新的候选人。
  3. 撤销对某候选人的投票(假设每个人的投票可以被追踪和修改)。
  4. 实时更新并显示投票结果。

实现代码

首先,我们将定义一个投票管理系统,包括添加候选人、投票和撤销投票的功能。然后,我们将展示如何使用这个系统来进行投票活动。

package mainimport ("fmt"
)// VoteSystem 投票系统结构体
type VoteSystem struct {votes      map[string]intcandidates map[string]bool
}// NewVoteSystem 创建一个新的投票系统
func NewVoteSystem() *VoteSystem {return &VoteSystem{votes:      make(map[string]int),candidates: make(map[string]bool),}
}// AddCandidate 添加一个新的候选人
func (vs *VoteSystem) AddCandidate(candidate string) {if _, exists := vs.candidates[candidate]; !exists {vs.candidates[candidate] = truevs.votes[candidate] = 0fmt.Println(candidate, "已添加为候选人")}
}// Vote 投票给一个候选人
func (vs *VoteSystem) Vote(candidate string) {if _, exists := vs.candidates[candidate]; exists {vs.votes[candidate]++fmt.Println("投票给", candidate, "成功")} else {fmt.Println(candidate, "不是一个有效的候选人")}
}// RevokeVote 撤销对某候选人的投票
func (vs *VoteSystem) RevokeVote(candidate string) {if votes, exists := vs.votes[candidate]; exists && votes > 0 {vs.votes[candidate]--fmt.Println("撤销对", candidate, "的投票成功")} else {fmt.Println("无法撤销投票,", candidate, "的得票数为 0 或他不是候选人")}
}// DisplayResults 显示投票结果
func (vs *VoteSystem) DisplayResults() {fmt.Println("投票结果:")for candidate, votes := range vs.votes {fmt.Printf("%s: %d 票\n", candidate, votes)}
}func main() {vs := NewVoteSystem()vs.AddCandidate("Alice")vs.AddCandidate("Bob")vs.Vote("Alice")vs.Vote("Bob")vs.Vote("Alice")vs.RevokeVote("Alice")vs.DisplayResults()
}

扩展功能

在上述基础功能之外,这个投票系统可以进一步扩展,例如:

  • 实现用户认证机制,确保每个用户只能投票一次。
  • 提供图形化界面(GUI),使用户可以更方便地进行投票和查看结果。
  • 支持网络功能,允许远程投票和结果实时更新。

通过这个案例的扩展,我们演示了如何使用 Go 语言构建一个功能完整的投票系统。这个系统不仅能够处理基本的投票需求,还具备了灵活的扩展性,能够适应更复杂的应用场景。掌握了如何构建这样的系统,你将能够在自己的项目中实现更高级的数据管理和用户交互功能。

3.2.3 拓展案例 1:库存管理

在零售和电子商务领域,库存管理是核心操作之一。有效的库存管理不仅能保证货物的供应,还能帮助商家减少存货成本,提高服务质量。通过这个案例,我们将构建一个简易的库存管理系统,该系统能够添加商品、更新库存数量,并提供库存查询功能。

功能描述

  1. 添加新商品到库存中。
  2. 更新现有商品的库存数量。
  3. 查询特定商品的库存数量。
  4. 列出当前库存中所有商品的信息。

实现代码

我们将使用 Go 语言中的映射(Map)来实现这个库存管理系统:

package mainimport ("fmt"
)// InventoryItem 表示库存中的单个项目
type InventoryItem struct {ID    stringName  stringStock int
}// InventoryManagement 库存管理系统
type InventoryManagement struct {items map[string]InventoryItem
}// NewInventoryManagement 创建一个新的库存管理系统
func NewInventoryManagement() *InventoryManagement {return &InventoryManagement{items: make(map[string]InventoryItem),}
}// AddItem 添加一个新商品
func (im *InventoryManagement) AddItem(id string, name string, stock int) {im.items[id] = InventoryItem{ID: id, Name: name, Stock: stock}fmt.Printf("添加商品 %s 到库存中\n", name)
}// UpdateStock 更新库存数量
func (im *InventoryManagement) UpdateStock(id string, stock int) {if item, exists := im.items[id]; exists {item.Stock = stockim.items[id] = itemfmt.Printf("更新了 %s 的库存数量为 %d\n", item.Name, stock)} else {fmt.Println("商品不存在于库存中")}
}// QueryStock 查询特定商品的库存数量
func (im *InventoryManagement) QueryStock(id string) {if item, exists := im.items[id]; exists {fmt.Printf("%s 的库存数量为 %d\n", item.Name, item.Stock)} else {fmt.Println("商品不存在于库存中")}
}// ListItems 列出库存中所有商品的信息
func (im *InventoryManagement) ListItems() {fmt.Println("库存中所有商品的信息:")for _, item := range im.items {fmt.Printf("ID: %s, 名称: %s, 库存数量: %d\n", item.ID, item.Name, item.Stock)}
}func main() {im := NewInventoryManagement()im.AddItem("001", "T恤", 50)im.UpdateStock("001", 48)im.QueryStock("001")im.ListItems()
}

扩展功能

在上述基础功能之外,库存管理系统可以进一步扩展,例如:

  • 实现库存警告机制,当某个商品的库存低于预设阈值时自动发出警告。
  • 支持批量操作,如批量添加商品或批量更新库存。
  • 集成销售系统,根据销售数据自动调整库存。

通过这个案例的扩展,我们展示了如何使用 Go 语言构建一个简易但功能完整的库存管理系统。这个系统不仅适用于零售和电子商务领域,也可以应用于其他需要库存管理的场景。掌握了如何构建这样的系统,你就能在自己的项目中实现更高效和自动化的库存管理功能。

3.2.4 拓展案例 2:员工目录

在大多数组织或企业中,管理员工信息是一个基本且关键的操作。有效的员工目录系统不仅能帮助快速查找员工信息,还能根据需要轻松更新和管理这些信息。通过这个案例,我们将构建一个简易的员工目录系统,该系统能够添加新员工、更新员工信息、删除员工记录,并提供查询功能。

功能描述

  1. 添加新员工到目录中。
  2. 更新现有员工的信息。
  3. 删除员工记录。
  4. 查询特定员工的信息。
  5. 列出目录中所有员工的信息。

实现代码

我们将使用 Go 语言中的映射(Map)来实现这个员工目录系统:

package mainimport ("fmt"
)// Employee 表示员工的信息
type Employee struct {ID        stringName      stringDepartment string
}// EmployeeDirectory 员工目录系统
type EmployeeDirectory struct {directory map[string]Employee
}// NewEmployeeDirectory 创建一个新的员工目录
func NewEmployeeDirectory() *EmployeeDirectory {return &EmployeeDirectory{directory: make(map[string]Employee),}
}// AddEmployee 添加一个新员工
func (ed *EmployeeDirectory) AddEmployee(id string, name string, department string) {ed.directory[id] = Employee{ID: id, Name: name, Department: department}fmt.Printf("员工 %s 已添加到目录中\n", name)
}// UpdateEmployee 更新员工信息
func (ed *EmployeeDirectory) UpdateEmployee(id string, name string, department string) {if _, exists := ed.directory[id]; exists {ed.directory[id] = Employee{ID: id, Name: name, Department: department}fmt.Printf("员工 %s 的信息已更新\n", name)} else {fmt.Println("员工不存在于目录中")}
}// DeleteEmployee 删除员工记录
func (ed *EmployeeDirectory) DeleteEmployee(id string) {if _, exists := ed.directory[id]; exists {delete(ed.directory, id)fmt.Println("员工记录已删除")} else {fmt.Println("员工不存在于目录中")}
}// QueryEmployee 查询特定员工的信息
func (ed *EmployeeDirectory) QueryEmployee(id string) {if employee, exists := ed.directory[id]; exists {fmt.Printf("员工信息:ID: %s, 名称: %s, 部门: %s\n", employee.ID, employee.Name, employee.Department)} else {fmt.Println("员工不存在于目录中")}
}// ListEmployees 列出目录中所有员工的信息
func (ed *EmployeeDirectory) ListEmployees() {fmt.Println("目录中所有员工的信息:")for _, employee := range ed.directory {fmt.Printf("ID: %s, 名称: %s, 部门: %s\n", employee.ID, employee.Name, employee.Department)}
}func main() {ed := NewEmployeeDirectory()ed.AddEmployee("001", "Alice", "技术部")ed.AddEmployee("002", "Bob", "市场部")ed.UpdateEmployee("001", "Alice Smith", "产品部")ed.QueryEmployee("001")ed.DeleteEmployee("002")ed.ListEmployees()
}

扩展功能

在上述基础功能之外,员工目录系统可以进一步扩展,例如:

  • 支持按部门查询员工。
  • 实现一个图形化界面(GUI)或网页界面,使用户交云界面更加友好。
  • 集成到企业的人力资源管理系统中,实现数据同步。

通过这个案例的扩展,我们展示了如何使用 Go 语言构建一个简易但功能完整的员工目录系统。这个系统不仅适用于小型企业或团队,也可以作为更大系统中的一个模块。掌握了如何构建这样的系统,你就能在自己的项目中实现更高效和系统化的信息管理功能。

3.3 结构体与方法:Go 语言的构建块

Ahoy! 在 Go 语言的宝库中,结构体(Struct)是构建复杂数据模型的基石,而方法(Method)则让这些结构体不仅仅是静态的数据集合,而是能够执行操作的实体。就像在乐高世界里,结构体是你手中的积木块,方法则是让积木动起来的魔法。让我们一起探索这些强大的工具,看看如何在 Go 中使用它们来构建和操纵复杂的数据结构。

3.3.1 基础知识讲解

结构体(Struct)

结构体是一种聚合数据类型,它允许你将多个不同类型的项(称为字段)组合成一个单一的复合类型。每个字段都有一个名称和一个类型。

type Person struct {Name    stringAge     intAddress string
}

方法(Method)

方法是附加到类型上的函数。在 Go 中,你可以为任何类型定义方法,包括结构体类型。方法的定义与函数类似,但它在函数名之前有一个额外的参数,称为接收器(Receiver),表示该方法附加到的类型。

func (p Person) Introduce() {fmt.Printf("Hi, I'm %s, %d years old.\n", p.Name, p.Age)
}

3.3.2 重点案例:图书管理系统

在图书管理系统中,我们已经探索了添加图书、搜索图书以及借阅图书的基本功能。现在,我们将进一步扩展这个系统,添加返回图书和列出所有图书的功能,以及实现一个简单的用户界面,让用户可以通过命令行与系统交互。

功能描述

  1. 添加新书到图书馆。
  2. 根据书名搜索图书。
  3. 借阅图书,并更新图书的借阅状态。
  4. 返回图书,并更新图书的借阅状态。
  5. 列出图书馆所有图书的信息。
  6. 实现命令行用户界面。

实现代码

首先,我们将在 BookLibrary 结构体上添加新的方法,然后创建一个简单的命令行界面来与用户交互。

package mainimport ("bufio""fmt""os""strings"
)// Book 定义图书结构体
type Book struct {Title     stringAuthor    stringISBN      stringAvailable bool
}// Library 定义图书馆结构体
type Library struct {Collection []Book
}// AddBook 添加新书到图书馆
func (l *Library) AddBook(book Book) {l.Collection = append(l.Collection, book)
}// FindBook 搜索图书
func (l *Library) FindBook(title string) *Book {for i := range l.Collection {if l.Collection[i].Title == title {return &l.Collection[i]}}return nil
}// BorrowBook 借阅图书
func (b *Book) BorrowBook() bool {if b.Available {b.Available = falsereturn true}return false
}// ReturnBook 返回图书
func (b *Book) ReturnBook() {b.Available = true
}// ListBooks 列出所有图书
func (l *Library) ListBooks() {for _, book := range l.Collection {fmt.Printf("Title: %s, Author: %s, ISBN: %s, Available: %t\n", book.Title, book.Author, book.ISBN, book.Available)}
}// 用户界面
func main() {library := Library{}scanner := bufio.NewScanner(os.Stdin)for {fmt.Println("\nWelcome to the Library")fmt.Println("1. Add Book")fmt.Println("2. Find Book")fmt.Println("3. Borrow Book")fmt.Println("4. Return Book")fmt.Println("5. List Books")fmt.Println("6. Exit")fmt.Print("Enter option: ")scanner.Scan()option := scanner.Text()switch option {case "1":fmt.Print("Enter title: ")scanner.Scan()title := scanner.Text()fmt.Print("Enter author: ")scanner.Scan()author := scanner.Text()fmt.Print("Enter ISBN: ")scanner.Scan()isbn := scanner.Text()library.AddBook(Book{Title: title, Author: author, ISBN: isbn, Available: true})fmt.Println("Book added.")case "2":fmt.Print("Enter title: ")scanner.Scan()title := scanner.Text()book := library.FindBook(title)if book != nil {fmt.Printf("Book found: %+v\n", *book)} else {fmt.Println("Book not found.")}case "3":fmt.Print("Enter title: ")scanner.Scan()title := scanner.Text()book := library.FindBook(title)if book != nil && book.BorrowBook() {fmt.Println("Book borrowed.")} else {fmt.Println("Book not available.")}case "4":fmt.Print("Enter title: ")scanner.Scan()title := scanner.Text()book := library.FindBook(title)if book != nil {book.ReturnBook()fmt.Println("Book returned.")} else {fmt.Println("Book not found.")}case "5":library.ListBooks()case "6":fmt.Println("Goodbye!")returndefault:fmt.Println("Invalid option.")}}
}

通过这个案例的扩展,我们不仅增强了图书管理系统的功能,还实现了一个简单的命令行界面,使用户能够更方便地与系统交互。这种类型的系统可以根据需要进一步扩展,比如添加用户管理、图书预约等功能。掌握了如何构建和扩展这样的系统,你就能在自己的项目中实现更复杂和用户友好的应用程序。

3.3.3 拓展案例 1:员工管理系统

在任何组织中,有效地管理员工信息是至关重要的。通过这个案例,我们将构建一个简易的员工管理系统,使管理员能够添加新员工、更新员工信息、删除员工记录,并查询特定员工的信息。

功能描述

  1. 添加新员工到系统中。
  2. 更新现有员工的信息。
  3. 删除员工记录。
  4. 查询特定员工的信息。
  5. 列出系统中所有员工的信息。

实现代码

我们将使用结构体来表示员工信息,并为这个员工管理系统定义一系列方法来处理员工数据。

package mainimport ("fmt"
)// Employee 定义员工信息的结构体
type Employee struct {ID       stringName     stringPosition string
}// EmployeeManager 管理员工信息的结构体
type EmployeeManager struct {employees map[string]Employee
}// NewEmployeeManager 创建一个新的员工管理器
func NewEmployeeManager() *EmployeeManager {return &EmployeeManager{employees: make(map[string]Employee)}
}// AddEmployee 添加新员工
func (em *EmployeeManager) AddEmployee(id, name, position string) {em.employees[id] = Employee{ID: id, Name: name, Position: position}fmt.Println("成功添加员工:", name)
}// UpdateEmployee 更新员工信息
func (em *EmployeeManager) UpdateEmployee(id, name, position string) {if _, exists := em.employees[id]; exists {em.employees[id] = Employee{ID: id, Name: name, Position: position}fmt.Println("成功更新员工信息:", name)} else {fmt.Println("员工不存在:", name)}
}// DeleteEmployee 删除员工
func (em *EmployeeManager) DeleteEmployee(id string) {if _, exists := em.employees[id]; exists {delete(em.employees, id)fmt.Println("成功删除员工:", id)} else {fmt.Println("员工不存在:", id)}
}// QueryEmployee 查询员工信息
func (em *EmployeeManager) QueryEmployee(id string) {if emp, exists := em.employees[id]; exists {fmt.Printf("员工信息: ID: %s, 姓名: %s, 职位: %s\n", emp.ID, emp.Name, emp.Position)} else {fmt.Println("员工不存在:", id)}
}// ListEmployees 列出所有员工
func (em *EmployeeManager) ListEmployees() {fmt.Println("所有员工信息:")for _, emp := range em.employees {fmt.Printf("ID: %s, 姓名: %s, 职位: %s\n", emp.ID, emp.Name, emp.Position)}
}func main() {manager := NewEmployeeManager()manager.AddEmployee("001", "Alice", "Software Engineer")manager.AddEmployee("002", "Bob", "Project Manager")manager.UpdateEmployee("001", "Alice Smith", "Senior Software Engineer")manager.QueryEmployee("001")manager.DeleteEmployee("002")manager.ListEmployees()
}

扩展功能

在上述基础功能之外,员工管理系统可以进一步扩展,例如:

  • 支持按职位或其他属性过滤员工。
  • 实现图形化用户界面(GUI)或Web界面,使系统更易于使用。
  • 集成到更大的人力资源管理系统中,提供更全面的功能。

通过这个案例的扩展,我们展示了如何使用 Go 语言构建一个简易但功能完整的员工管理系统。这个系统不仅能够满足基本的员工信息管理需求,还具备良好的扩展性,可以根据实际业务需求进行定制和扩展。掌握了如何构建这样的系统,你就能在自己的项目中实现更高效和系统化的员工信息管理。

3.3.4 拓展案例 2:在线商店的购物车

在电子商务领域,购物车是一个核心功能,它允许用户在浏览商品时选择想要购买的商品,并最终进行结算。通过这个案例,我们将构建一个简易的购物车系统,该系统能够添加商品到购物车、删除购物车中的商品、计算购物车中所有商品的总价,并列出购物车中的商品。

功能描述

  1. 添加商品到购物车。
  2. 删除购物车中的商品。
  3. 计算购物车中所有商品的总价。
  4. 列出购物车中的所有商品。

实现代码

我们将定义一个Product结构体来表示商品,以及一个Cart结构体来表示购物车。购物车将包含一个商品切片作为其内容。

package mainimport ("fmt"
)// Product 定义商品信息
type Product struct {ID    stringName  stringPrice float64
}// Cart 定义购物车
type Cart struct {Products []Product
}// NewCart 创建一个新的购物车实例
func NewCart() *Cart {return &Cart{}
}// AddProduct 向购物车中添加商品
func (c *Cart) AddProduct(product Product) {c.Products = append(c.Products, product)fmt.Printf("已添加商品 \"%s\" 到购物车\n", product.Name)
}// RemoveProduct 从购物车中删除商品
func (c *Cart) RemoveProduct(ID string) {for i, product := range c.Products {if product.ID == ID {c.Products = append(c.Products[:i], c.Products[i+1:]...)fmt.Printf("已从购物车删除商品 \"%s\"\n", product.Name)return}}fmt.Println("未找到商品,无法从购物车删除")
}// CalculateTotal 计算购物车中所有商品的总价
func (c *Cart) CalculateTotal() float64 {var total float64for _, product := range c.Products {total += product.Price}return total
}// ListProducts 列出购物车中的所有商品
func (c *Cart) ListProducts() {fmt.Println("购物车中的商品:")for _, product := range c.Products {fmt.Printf("ID: %s, 名称: %s, 价格: %.2f\n", product.ID, product.Name, product.Price)}
}func main() {cart := NewCart()cart.AddProduct(Product{ID: "001", Name: "Go语言圣经", Price: 56.00})cart.AddProduct(Product{ID: "002", Name: "键盘", Price: 199.00})cart.ListProducts()fmt.Printf("购物车总价: %.2f\n", cart.CalculateTotal())cart.RemoveProduct("001")cart.ListProducts()
}

扩展功能

在上述基础功能之外,购物车系统可以进一步扩展,例如:

  • 支持商品数量的增减,而不仅仅是添加或删除商品。
  • 实现优惠券或折扣功能,自动计算折后价格。
  • 集成到在线支付系统,支持一键结算功能。

通过这个案例的扩展,我们演示了如何使用 Go 语言构建一个简易但功能完整的购物车系统。这个系统不仅适用于小型或个人项目,也可以作为更大电子商务系统中的一个模块。掌握了如何构建这样的系统,你就能在自己的电商项目中实现更高效和用户友好的购物体验。

相关文章:

《Go 简易速速上手小册》第3章:数据结构(2024 最新版)

文章目录 3.1 数组与切片&#xff1a;Go 语言的动态队伍3.1.1 基础知识讲解3.1.2 重点案例&#xff1a;动态成绩单功能描述实现代码扩展功能 3.1.3 拓展案例 1&#xff1a;数据分析功能描述实现代码扩展功能 3.1.4 拓展案例 2&#xff1a;日志过滤器功能描述实现代码扩展功能 3…...

雷达模拟触摸屏,支持tuio\鼠标\Touch

案例展示&#xff1a; 雷达精度测试 星秒雷达互动软件测试 功能说明&#xff1a; 雷达互动系统支持各种品牌雷达&#xff0c;支持4-256点校准&#xff08;校准点越大精度越高 &#xff0c;而市场上基本都是4点校准 &#xff0c;碰到大面积范围无法保证精准度&#xff09;&…...

一文了解大数据生态

大数据一词最早指的是传统数据处理应用软件无法处理的过于庞大或过于复杂的数据集。 现在&#xff0c;对“大数据”一词的使用倾向于使用预测分析、用户行为分析或者其他一些从大数据中提取价值的高级数据分析方法&#xff0c;很少用于表示特定规模的数据集。 定义 大数据是…...

Linux篇:指令

一 基本常识&#xff1a; 1. 文件文件内容文件的属性 2. 文件的操作对文件内容的操作对文件属性的操作 3. 文件的类型&#xff1a; d&#xff1a;目录文件 -&#xff1a;普通文件 4. 指令是可执行程序&#xff0c;指令的代码文件在系统的某一个位置存在的。/u…...

Linux eject命令教程:如何控制可移动介质的弹出和收回(附案例详解和注意事项)

Linux eject命令介绍 eject命令在Linux中用于弹出可移动介质&#xff0c;通常是CD-ROM、软盘、磁带或JAZ或ZIP磁盘。您还可以使用此命令来控制一些多盘CD-ROM切换器&#xff0c;一些设备支持的自动弹出功能&#xff0c;以及关闭一些CD-ROM驱动器的光盘托盘。 Linux eject命令…...

【已解决】PPT无法复制内容怎么办?

想要复制PPT文件里的内容&#xff0c;却发现复制不了&#xff0c;怎么办&#xff1f; 这种情况&#xff0c;一般是PPT文件被设置了以“只读方式”打开&#xff0c;“只读方式”下的PPT无法进行编辑更改&#xff0c;也无法进行复制粘贴的操作。 想要解决这个问题&#xff0c;我…...

六大设计原则 (SOLID)

一、设计原则概述 古人云: 有道无术,术可求.有术无道,止于术. 而设计模式通常需要遵循一些设计原则,在设计原则的基础之上衍生出了各种各样的设计模式。设计原则是设计要求,设计模式是设计方案,使用设计模式的代码则是具体的实现。 设计模式中主要有六大设计原则,简称为SOL…...

深度解析Sora的核心技术

Sora要解决的核心问题 Sora面临的挑战是将不同类型的视觉信息&#xff0c;如视频、文本、图像和声音等&#xff0c;整合为一种共同的表征形式。这种转换是实现统一训练过程的关键&#xff0c;旨在将各类数据集中到一个训练框架中&#xff0c;以便于进行大规模的统一学习。简而…...

设计模式面试系列-02

1. Java 中工厂模式有什么优势? 1、工厂模式是最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。 2、利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。 3、将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。 2. …...

MKdocs添加顶部公告栏

效果如图&#xff1a; docs/overrides下新建main.html &#xff0c;针对main.html文件 树状结构如下: $ tree -a . ├── .github │ ├── .DS_Store │ └── workflows │ └── PublishMySite.yml ├── docs │ └── index.md │ └──overrides │…...

Android全新UI框架之常用ComposeUI组件

在Compose中&#xff0c;每个组件都是一个带有Composable注解的函数&#xff0c;被称为Composable。Compose已经预置了很多基于MD设计规范的Composable组件。 在布局方面&#xff0c;Compose提供了Column、Row、Box三种布局组件(感觉跟flutter差不多)&#xff0c;类似于传统视图…...

网络防御保护综合练习

一、实验拓扑 二、实验要求 1, Fw1和Fw2组成主备模式的双机热备 2&#xff0c;DMZ区存在两台服务器&#xff0c;现在要求生产区的设备仅能在办公时间&#xff08;9&#xff1a;00 - 18&#xff1a;00&#xff09;访问&#xff0c;办公区的设备全天都可以访问。 3&#xff0c;办…...

Unity调用文心-ERNIE-Bot-turbo

参考文章 ERNIE-Bot-turbo - 千帆大模型平台 | 百度智能云文档 (baidu.com) 错误码 - 千帆大模型平台 | 百度智能云文档 (baidu.com) private readonly string apiKey "";private readonly string secretKey "";private readonly string tokenUrl &q…...

机器学习基本概念(李宏毅课程)

目录 一、概念:1、机器学习概念:2、深度学习概念&#xff1a; 二、深度学习中f(.)的输入和输出&#xff1a;1、输入&#xff1a;2、输出&#xff1a; 三、三种机器学习任务&#xff1a;1、Regression回归任务介绍&#xff1a;2、Classification分类任务介绍&#xff1a;3、Stru…...

浅谈WPF之利用RichTextBox实现富文本编辑器

在实际应用中&#xff0c;富文本随处可见&#xff0c;如留言板&#xff0c;聊天软件&#xff0c;文档编辑&#xff0c;特定格式内容等&#xff0c;在WPF开发中&#xff0c;如何实现富文本编辑呢&#xff1f;本文以一个简单的小例子&#xff0c;简述如何通过RichTextBox实现富文…...

w29pikachu-ssrf实例

SSRF简介 SSRF是服务器端请求伪造 危害&#xff1a; 1.可以对服务器所在内网、本地进行端口扫描&#xff0c;获取一些服务的信息等 2.目标网站本地敏感数据的读取 3.内外网主机应用程序漏洞的利用 4.内外网web站点漏洞的利用 ssrf常用的相关协议&#xff1a; gopher://: 发…...

使用 openssl 进行哈希计算

版本&#xff1a;OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022) SHAx 系列 如果对象完全存储在内存中&#xff0c;可以使用以下函数&#xff1a; #include <openssl/sha.h>unsigned char *SHA1(const unsigned char *data, size_t count, unsigned…...

深度学习基础——SSD目标检测

SSD网络介绍 使用多个特征图作为特征预测层。 SSD (Single Shot MultiBox Detector)于2016年提出。当网络输入为300300大小时&#xff0c;在VOC2007测试集上达到74.3%的mAP;当输入是512512大小时&#xff0c;达到了76.9%的mAP SSD_Backbone部分介绍 不变的部分 特征提取网…...

鸿蒙系统优缺点,能否作为开发者选择

凡是都有对立面&#xff0c;就直接说说鸿蒙的优缺点吧。 鸿蒙的缺点&#xff1a; 鸿蒙是从2019年开始做出来的&#xff0c;那时候是套壳Android大家都知晓。从而导致大家不看鸿蒙系统&#xff0c;套壳Android就是多次一举。现在鸿蒙星河版已经是纯血鸿蒙&#xff0c;但是它的…...

强化学习入门(Matlab2021b)-创建环境【2】

目录 1 前言2 利用step和reset函数创建自定义环境2.1 对象描述2.2 reset函数2.3 step函数2.3 构建自定义环境3 使用匿名函数传递额外的参数4 可视化检查自定义函数的输出参考链接1 前言 本文介绍如何基于MATLAB编写step、reset函数,创建自己的强化学习环境(Environment)。 使…...

OkHttp 相关问题

1、OkHttp请求整体流程是怎么样? ​ Request-》OkHttpClient-》RealCall 同步 -》 在调用线程 执行五大拦截器 异步 -》 使用分发器将任务在线程池执行 五大拦截器 ---首先AsyncCall --加到等待队列readyAsyncCalls--》判断host有没有 已经存在。有,就赋值原来的。(reuseC…...

html的表单标签(上):form标签和input标签

表单标签 表单是让用户输入信息的重要途径。 用表单标签来完成与服务器的一次交互&#xff0c;比如你登录QQ账号时的场景。 表单分成两个部分&#xff1a; 表单域&#xff1a;包含表单元素的区域&#xff0c;用form标签来表示。表单控件&#xff1a;输入框&#xff0c;提交按…...

网页数据的解析提取(XPath的使用----lxml库详解)

在提取网页信息时&#xff0c;最基础的方法是使用正则表达式&#xff0c;但过程比较烦琐且容易出错。对于网页节点来说&#xff0c;可以定义id、class或其他属性&#xff0c;而且节点之间还有层次关系&#xff0c;在网页中可以通过XPath或CSS选择器来定位一个或多个节点。那么&…...

dell r740服务器黄灯闪烁维修现场解决

1&#xff1a;首先看一下这款DELL非常主力的PowerEdge R740服务器长啥样&#xff0c;不得不说就外观来说自从IBM抛弃System X系列服务器后&#xff0c;也就戴尔这个外观看的比较顺眼。 图一&#xff1a;是DELL R740前视图&#xff08;这款是8盘机型&#xff09; 图二&#xff…...

202426读书笔记|《尼采诗精选》——高蹈于生活之上,提升自己向下观望

202426读书笔记|《尼采诗精选》——高蹈于生活之上&#xff0c;提升自己向下观望 第一辑 早期尼采诗歌选辑&#xff08;1858—1869年&#xff09;第二辑 前期尼采遗著中的诗歌选辑&#xff08;1871—1882年&#xff09;第五辑 戏谑、狡计与复仇——德语韵律短诗序曲&#xff08…...

【PX4学习笔记】13.飞行安全与炸机处理

目录 文章目录 目录使用QGC地面站的安全设置、安全绳安全参数在具体参数中的体现安全绳 无人机炸机处理A&#xff1a;无人机异常时控操作B&#xff1a;无人机炸机现场处理C&#xff1a;无人机炸机后期维护和数据处理D&#xff1a;无人机再次正常飞行测试 无人机飞行法律宣传 使…...

Puppeteer 使用实战:如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客(二)

文章目录 上一篇效果演示Puppeteer 修改浏览器的默认下载位置控制并发数错误重试并发控制 错误重试源码 上一篇 Puppeteer 使用实战&#xff1a;如何将自己的 CSDN 专栏文章导出并用于 Hexo 博客&#xff08;一&#xff09; 效果演示 上一篇实现了一些基本功能&#xff0c;…...

[ 2024春节 Flink打卡 ] -- 优化(draft)

2024&#xff0c;游子未归乡。工作需要&#xff0c;flink coding。觉知此事要躬行&#xff0c;未休&#xff0c;特记 资源配置调优内存设置 TaskManager内存模型 https://nightlies.apache.org/flink/flink-docs-release-1.18/docs/deployment/config/ TaskManager 内存模型…...

电脑进水无法开机怎么办 电脑进水开不了机的解决方法

意外总是会不定时打破你的计划&#xff0c;电脑这类电器最怕遇到的除了火还有水&#xff0c;设备进水会导致数据丢失&#xff0c;那么我们遇到电脑进水怎么办&#xff1f;进水之后不正确处理也会引起很多不必要的麻烦. 解决办法 第一步&#xff1a;关机 如果您的电脑是在开…...

【Flutter】底部导航BottomNavigationBar的使用

常用基本属性 属性名含义是否必须items底部导航栏的子项List是currentIndex当前显示索引否onTap底部导航栏的点击事件&#xff0c; Function(int)否type底部导航栏类型&#xff0c;定义 [BottomNavigationBar] 的布局和行为否selectedItemColor选中项图标和label的颜色否unsel…...