单元1 · Go 开发环境与基础入门
安装 Go、go run、变量、常量、fmt 输出、注释与命名规范
- 包与入口:Go 程序以 package main 开头,执行入口是 main 函数。
- 输出:fmt.Println 自动换行,fmt.Printf 支持格式化占位符。
- 变量:var 声明变量,:= 简短声明并推断类型;const 声明常量。
- 命名规范:导出标识符大写字母开头,包内私有小写。
实训1.1 Hello World 与包结构
编写第一个 Go 程序:定义 main 包和 main 函数,用 fmt.Println 输出一行问候语。
Go 程序从 main 包的 main 函数开始执行;导入 fmt 包后调用 fmt.Println 输出。
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
实训1.2 变量声明与常量
声明一个整型变量 age 为 21,一个字符串常量 name 为 Go,分别输出它们的值。
Go 中变量可用 var 声明,也可用 := 简短声明;常量用 const 声明且不可修改。
package main
import "fmt"
func main() {
var age int = 21
const name = "Go"
fmt.Println("age =", age)
fmt.Println("name =", name)
}
实训1.3 多变量赋值与交换
声明 a=10、b=20,交换两个变量的值后输出;要求不使用临时变量。
Go 支持多重赋值,a, b = b, a 即可一步完成交换。
package main
import "fmt"
func main() {
a, b := 10, 20
fmt.Println("交换前:", a, b)
a, b = b, a
fmt.Println("交换后:", a, b)
}
实训1.4 fmt 格式化输出
用 fmt.Printf 按格式输出:整型(十进制/二进制/十六进制)、浮点(保留两位)、字符串。
fmt.Printf 的占位符:%d 十进制、%b 二进制、%x 十六进制、%.2f 保留两位小数、%s 字符串。
package main
import "fmt"
func main() {
n := 42
pi := 3.14159
name := "Gopher"
fmt.Printf("十进制:%d,二进制:%b,十六进制:%x\n", n, n, n)
fmt.Printf("浮点:%.2f\n", pi)
fmt.Printf("字符串:%s\n", name)
}
单元2 · 变量、数据类型与运算符
整型/浮点/字符串/布尔、算术/比较/逻辑运算符、类型转换
- 数据类型:int/float64/string/bool 为常用基础类型。
- 运算符:/ 整除、% 取余、&& 与、|| 或、! 非。
- 类型转换:T(x) 显式转换;strconv 包处理字符串与数字互转。
实训2.1 基础运算:加、减、乘、除、取余
给定整数 17 和 5,输出它们的和、差、积、商(整除)和余数。
Go 中 / 对两个整数执行整除,% 取余;int 类型运算结果仍为 int。
package main
import "fmt"
func main() {
a, b := 17, 5
fmt.Println("和:", a+b)
fmt.Println("差:", a-b)
fmt.Println("积:", a*b)
fmt.Println("整除商:", a/b)
fmt.Println("余数:", a%b)
}
实训2.2 浮点运算与类型转换
计算圆的周长与面积:半径 r=7.5,圆周率取 3.14159。
浮点常量参与运算;可把整型转 float64 后再做浮点除法,避免整除截断。
package main
import "fmt"
func main() {
r := 7.5
pi := 3.14159
circumference := 2 * pi * r
area := pi * r * r
fmt.Printf("周长:%.4f\n", circumference)
fmt.Printf("面积:%.4f\n", area)
}
实训2.3 比较与逻辑运算
a=8、b=12,判断并输出 a 是否大于 b、a 与 b 是否不相等、a<10 且 b>10 是否成立。
比较运算符返回布尔值;逻辑与用 &&、逻辑或用 ||、取反用 !。
package main
import "fmt"
func main() {
a, b := 8, 12
fmt.Println("a > b:", a > b)
fmt.Println("a != b:", a != b)
fmt.Println("a<10 且 b>10:", a < 10 && b > 10)
fmt.Println("!(a==8):", !(a == 8))
}
实训2.4 类型转换综合
将字符串形式的整数 "42" 转换为 int,加上 8 后转为 float64,再转为字符串拼接输出。
strconv.Atoi 转整数,float64() 转浮点,strconv.Itoa 或 fmt.Sprint 转字符串。
package main
import (
"fmt"
"strconv"
)
func main() {
s := "42"
n, _ := strconv.Atoi(s)
sum := n + 8
f := float64(sum)
text := fmt.Sprintf("%.1f", f)
fmt.Println("转换结果:", text)
}
单元3 · 流程控制:分支结构
if/else if/else、switch 语句
- if 语句:条件不需要括号,必须使用花括号。
- if 初始化:if x := expr; 条件 { } 可在条件前声明局部变量。
- switch:默认自动 break;可省略表达式实现 if-else 链。
实训3.1 if 判断成绩等级
输入成绩 score=85,输出等级:>=90 优秀、>=80 良好、>=60 及格、否则不及格。
用 if / else if / else 逐级判断;注意 Go 中条件不需要括号。
package main
import "fmt"
func main() {
score := 85
if score >= 90 {
fmt.Println("优秀")
} else if score >= 80 {
fmt.Println("良好")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
}
实训3.2 if 语句中声明变量
判断一个整数 n=15 的奇偶性,并利用 if 初始化语句输出 n 的平方是否大于 200。
Go 的 if 支持在条件前加初始化语句,如 if x := f(); 条件 { },x 作用域限于 if 块。
package main
import "fmt"
func main() {
n := 15
if n%2 == 0 {
fmt.Println(n, "是偶数")
} else {
fmt.Println(n, "是奇数")
}
if square := n * n; square > 200 {
fmt.Println("平方", square, "大于 200")
}
}
实训3.3 switch 判断星期
用 switch 把数字 1-7 映射为星期一至星期日,输入 4 输出对应星期。
Go 的 switch 默认每个 case 自动 break,无需写 break;可带初始化语句。
package main
import "fmt"
func main() {
day := 4
switch day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
case 4:
fmt.Println("星期四")
case 5:
fmt.Println("星期五")
case 6:
fmt.Println("星期六")
case 7:
fmt.Println("星期日")
default:
fmt.Println("无效输入")
}
}
实训3.4 switch 无表达式用法
用 switch 判断分数 72 的等级(>=90 优秀、>=60 及格、否则不及格),不写条件表达式。
Go 的 switch 可省略表达式,相当于 if-else 链;每个 case 写布尔条件。
package main
import "fmt"
func main() {
score := 72
switch {
case score >= 90:
fmt.Println("优秀")
case score >= 60:
fmt.Println("及格")
default:
fmt.Println("不及格")
}
}
单元4 · 循环结构
for 循环、break/continue、range 遍历
- for 循环:Go 只有 for,三种形式:标准、while、无限循环。
- range:遍历数组/切片/map,返回索引与值。
- 控制:break 终止循环,continue 跳过当前迭代。
实训4.1 for 求和 1 到 100
用 for 循环计算 1+2+...+100 的和并输出。
Go 只有 for 一种循环;for i := 1; i <= 100; i++ { } 是标准写法。
package main
import "fmt"
func main() {
sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
fmt.Println("1 到 100 的和:", sum)
}
实训4.2 打印乘法表
输出 9x9 乘法表,格式为 1x1=1 2x1=2 ...(每行一个乘数)。
嵌套两层 for 循环;内层循环次数随外层 i 变化;fmt.Printf 控制对齐。
package main
import "fmt"
func main() {
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%dx%d=%d ", j, i, i*j)
}
fmt.Println()
}
}
实训4.3 break 与 continue
输出 1 到 20 中所有能被 3 整除的数;遇到 15 时用 break 提前结束。
continue 跳过当前迭代,break 终止整个循环。
package main
import "fmt"
func main() {
for i := 1; i <= 20; i++ {
if i == 15 {
break
}
if i%3 != 0 {
continue
}
fmt.Println(i)
}
}
实训4.4 range 遍历切片求和
给定切片 nums := []int{3, 8, 15, 22, 7},用 range 遍历计算总和与平均值。
range 遍历切片返回索引和值;用 _ 忽略索引;平均值用 float64 转换。
package main
import "fmt"
func main() {
nums := []int{3, 8, 15, 22, 7}
sum := 0
for _, v := range nums {
sum += v
}
avg := float64(sum) / float64(len(nums))
fmt.Println("总和:", sum)
fmt.Printf("平均值:%.2f\n", avg)
}
单元5 · 函数基础
函数定义、参数返回值、多返回值、命名返回值
- 函数声明:func 名(参数) 返回类型 { }。
- 多返回值:Go 函数可返回多个值,常用于返回结果和错误。
- 可变参数:...T 接收任意数量参数,函数内以切片访问。
实训5.1 定义求和函数
定义函数 add(a, b int) int 返回两数之和,在 main 中调用并输出结果。
Go 函数声明:func 函数名(参数) 返回类型 { };同类型参数可合并声明。
package main
import "fmt"
func add(a, b int) int {
return a + b
}
func main() {
result := add(10, 20)
fmt.Println("10 + 20 =", result)
}
实训5.2 多返回值
定义函数 divMod(a, b int) (int, int) 返回商和余数,在 main 中分别接收并输出。
Go 函数可返回多个值,用圆括号列出返回类型;调用时用多个变量接收。
package main
import "fmt"
func divMod(a, b int) (int, int) {
return a / b, a % b
}
func main() {
q, r := divMod(17, 5)
fmt.Println("商:", q, "余数:", r)
}
实训5.3 判断质数函数
定义 isPrime(n int) bool 判断一个数是否为质数,输出 29 和 30 的判断结果。
质数是大于 1 且只能被 1 和自身整除的数;循环到 n 的平方根即可判断。
package main
import (
"fmt"
"math"
)
func isPrime(n int) bool {
if n < 2 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
if n%i == 0 {
return false
}
}
return true
}
func main() {
fmt.Println("29 是质数:", isPrime(29))
fmt.Println("30 是质数:", isPrime(30))
}
实训5.4 可变参数函数
定义函数 sumAll(nums ...int) int 接收任意多个整数并求和,分别传入 3 个和 5 个数测试。
Go 用 ...int 声明可变参数,函数内以切片方式访问;调用时逐个传参。
package main
import "fmt"
func sumAll(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println("sumAll(1,2,3) =", sumAll(1, 2, 3))
fmt.Println("sumAll(1,2,3,4,5) =", sumAll(1, 2, 3, 4, 5))
}
单元6 · 数组与切片
数组声明、切片操作、append、copy
- 数组:长度固定,[N]T 声明;值类型,赋值会拷贝。
- 切片:动态数组,[]T 声明;append 追加、copy 复制。
- 切片操作:s[i:j] 截取子切片;删除元素用 append 组合。
实训6.1 数组遍历求最大值
声明长度为 5 的整型数组 [5]int{12, 45, 7, 89, 33},遍历找出最大值并输出。
Go 数组长度固定;用 for i := 0; i < len(arr); i++ 或 range 遍历。
package main
import "fmt"
func main() {
arr := [5]int{12, 45, 7, 89, 33}
max := arr[0]
for _, v := range arr {
if v > max {
max = v
}
}
fmt.Println("最大值:", max)
}
实训6.2 切片追加与删除
创建切片 fruits 包含三个字符串,用 append 追加两个,再删除索引 1 的元素,输出结果。
append 追加元素;删除切片中间元素用 append(s[:i], s[i+1:]...) 组合。
package main
import "fmt"
func main() {
fruits := []string{"苹果", "香蕉", "橙子"}
fruits = append(fruits, "葡萄", "西瓜")
fmt.Println("追加后:", fruits)
// 删除索引 1 的元素
fruits = append(fruits[:1], fruits[2:]...)
fmt.Println("删除后:", fruits)
}
实训6.3 切片拷贝
将切片 src := []int{1,2,3,4,5} 拷贝到新切片 dst(容量相同),修改 dst[0]=99 后输出两个切片。
copy(dst, src) 拷贝元素;注意直接赋值 a:=b 是共享底层数组,copy 才是真正复制。
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
copy(dst, src)
dst[0] = 99
fmt.Println("src:", src)
fmt.Println("dst:", dst)
}
实训6.4 二维数组求行和
定义二维数组 matrix := [3][3]int{...},计算每一行的和并输出。
二维数组用 [行][列]T 声明;外层遍历行,内层遍历列累加。
package main
import "fmt"
func main() {
matrix := [3][3]int{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
for i, row := range matrix {
sum := 0
for _, v := range row {
sum += v
}
fmt.Printf("第 %d 行之和:%d\n", i+1, sum)
}
}
单元7 · map 与结构体
map 增删改查、结构体定义与初始化
- map:键值对集合,make 创建;m[k]=v 赋值、delete 删除。
- 键判断:v, ok := m[k] 的 ok 判断键是否存在。
- 结构体:type 定义;字段名方式初始化,点号访问字段。
实训7.1 map 基本操作
创建 map[string]int 存储三人的年龄,新增一人、修改一人,删除一人后遍历输出。
map 用 make 创建;增删改查:m[k]=v、delete(m,k)、v, ok := m[k]。
package main
import "fmt"
func main() {
ages := make(map[string]int)
ages["张三"] = 20
ages["李四"] = 22
ages["王五"] = 24
ages["赵六"] = 26
ages["李四"] = 23
delete(ages, "王五")
for name, age := range ages {
fmt.Println(name, "的年龄:", age)
}
}
实训7.2 map 键存在性判断
在 map 中查找指定键是否存在,分别测试存在的键和不存在的键。
用 v, ok := m[key] 的 ok 布尔值判断键是否存在,避免取到零值。
package main
import "fmt"
func main() {
scores := map[string]int{"语文": 90, "数学": 85}
for _, subj := range []string{"语文", "英语"} {
if v, ok := scores[subj]; ok {
fmt.Println(subj, "成绩:", v)
} else {
fmt.Println(subj, "不存在")
}
}
}
实训7.3 结构体定义与访问
定义 Student 结构体(Name string、Age int、Score float64),初始化一个学生并输出信息。
type 定义结构体;初始化可用字段名方式 Student{Name: "...", ...}。
package main
import "fmt"
type Student struct {
Name string
Age int
Score float64
}
func main() {
stu := Student{Name: "小明", Age: 18, Score: 92.5}
fmt.Println("姓名:", stu.Name)
fmt.Println("年龄:", stu.Age)
fmt.Println("成绩:", stu.Score)
}
实训7.4 结构体切片与统计
定义 Book 结构体,创建 3 本书的切片,找出价格最高的一本并输出。
结构体切片 []Book;遍历时用引用访问字段,比较 price 记录最高。
package main
import "fmt"
type Book struct {
Title string
Price float64
}
func main() {
books := []Book{
{Title: "Go 语言程序设计", Price: 59.0},
{Title: "算法导论", Price: 128.0},
{Title: "深入理解计算机系统", Price: 99.0},
}
max := books[0]
for _, b := range books {
if b.Price > max.Price {
max = b
}
}
fmt.Println("最贵的书:", max.Title, "价格:", max.Price)
}
单元8 · 方法与指针
方法定义、指针接收者、指针操作
- 方法:func (r Type) Method() { } 绑定到类型。
- 接收者:值接收者只读;指针接收者 (*T) 可修改原值。
- 指针:& 取地址,* 解引用;指针传递避免拷贝。
实训8.1 定义结构体方法
为 Rectangle 结构体(width、height)定义 Area() 方法,调用输出面积。
Go 方法:func (r Rectangle) Area() float64 { },接收者绑定到类型上。
package main
import "fmt"
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func main() {
rect := Rectangle{Width: 5, Height: 8}
fmt.Println("矩形面积:", rect.Area())
}
实训8.2 指针接收者修改字段
为 Counter 结构体定义 Inc() 方法(指针接收者)使计数加一,调用两次后输出计数。
指针接收者 (*Counter) 的方法可修改原结构体字段;值接收者只是副本。
package main
import "fmt"
type Counter struct {
count int
}
func (c *Counter) Inc() {
c.count++
}
func main() {
c := Counter{}
c.Inc()
c.Inc()
fmt.Println("计数:", c.count)
}
实训8.3 指针基础与解引用
声明变量 x=42,取指针 p 指向 x,通过指针修改 x 为 100 后输出 x。
&x 取地址,*p 解引用读取或修改指针指向的值。
package main
import "fmt"
func main() {
x := 42
p := &x
fmt.Println("x 的值:", x)
*p = 100
fmt.Println("通过指针修改后 x:", x)
}
实训8.4 方法链式调用
为 BankAccount 结构体定义 Deposit 和 Withdraw 方法(指针接收者),支持链式调用并输出余额。
指针接收者方法返回自身 (*BankAccount) 即可实现链式调用。
package main
import "fmt"
type BankAccount struct {
balance float64
}
func (b *BankAccount) Deposit(amount float64) *BankAccount {
b.balance += amount
return b
}
func (b *BankAccount) Withdraw(amount float64) *BankAccount {
if amount <= b.balance {
b.balance -= amount
}
return b
}
func main() {
acc := &BankAccount{}
acc.Deposit(1000).Withdraw(300).Deposit(200)
fmt.Println("账户余额:", acc.balance)
}
单元9 · 接口
接口定义、实现、类型断言
- 接口:type Shape interface { Area() float64 } 定义方法集。
- 隐式实现:类型实现接口全部方法即满足接口,无需显式声明。
- 类型断言:v, ok := i.(T) 安全断言接口的动态类型。
实训9.1 定义并实现接口
定义 Shape 接口(Area() float64),让 Circle 和 Square 实现它,分别输出面积。
Go 接口是隐式实现:类型只要实现接口的所有方法即自动满足接口。
package main
import "fmt"
type Shape interface {
Area() float64
}
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
type Square struct {
Side float64
}
func (s Square) Area() float64 {
return s.Side * s.Side
}
func main() {
var s Shape
s = Circle{Radius: 5}
fmt.Println("圆面积:", s.Area())
s = Square{Side: 4}
fmt.Println("正方形面积:", s.Area())
}
实训9.2 接口切片多态
创建 Shape 接口切片,放入一个圆和一个正方形,遍历调用 Area() 输出总面积。
接口切片 []Shape 可存放任意实现该接口的类型,实现多态。
package main
import "fmt"
type Shape interface {
Area() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
type Square struct{ Side float64 }
func (s Square) Area() float64 { return s.Side * s.Side }
func main() {
shapes := []Shape{Circle{Radius: 3}, Square{Side: 5}}
total := 0.0
for _, s := range shapes {
total += s.Area()
}
fmt.Printf("总面积:%.2f\n", total)
}
实训9.3 类型断言
把接口变量断言为具体类型,判断是否成功并输出结果。
用 v, ok := i.(ConcreteType) 做安全断言,ok 为 false 时不会 panic。
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "汪汪" }
type Cat struct{}
func (c Cat) Speak() string { return "喵喵" }
func main() {
var a Animal = Dog{}
if dog, ok := a.(Dog); ok {
fmt.Println("是狗,叫声:", dog.Speak())
} else {
fmt.Println("不是狗")
}
if cat, ok := a.(Cat); ok {
fmt.Println("是猫,叫声:", cat.Speak())
} else {
fmt.Println("不是猫")
}
}
单元10 · 错误处理
error 接口、fmt.Errorf、错误判断
- error 接口:内置接口含 Error() string;函数常返回 (结果, error)。
- 创建错误:errors.New 简单错误,fmt.Errorf 带格式化信息。
- 处理惯例:调用后立即检查 err != nil,及时返回或处理。
实训10.1 返回错误值
定义 divide(a, b float64) (float64, error),除数为 0 时返回错误,在 main 中处理。
Go 约定用 error 作为返回值传递错误;errors.New 或 fmt.Errorf 创建错误。
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为 0")
}
return a / b, nil
}
func main() {
if result, err := divide(10, 2); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result)
}
if _, err := divide(10, 0); err != nil {
fmt.Println("错误:", err)
}
}
实训10.2 带格式的错误信息
定义函数 findAge(ages map[string]int, name string) (int, error),找不到人时返回带名字的错误。
fmt.Errorf("%s 不存在", name) 可生成包含上下文的错误信息。
package main
import "fmt"
func findAge(ages map[string]int, name string) (int, error) {
if age, ok := ages[name]; ok {
return age, nil
}
return 0, fmt.Errorf("人员 %s 不存在", name)
}
func main() {
ages := map[string]int{"张三": 20, "李四": 22}
for _, name := range []string{"张三", "王五"} {
if age, err := findAge(ages, name); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println(name, "年龄:", age)
}
}
}
实训10.3 错误处理实战:读取成绩
模拟成绩检查:分数在 0-100 内返回等级,越界返回错误,测试合法与非法输入。
把校验逻辑封装为函数返回 error,main 中统一处理,体现 Go 的错误处理惯例。
package main
import "fmt"
func grade(score int) (string, error) {
if score < 0 || score > 100 {
return "", fmt.Errorf("非法分数:%d", score)
}
switch {
case score >= 90:
return "优秀", nil
case score >= 60:
return "及格", nil
default:
return "不及格", nil
}
}
func main() {
for _, s := range []int{95, 72, 120} {
if g, err := grade(s); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println(s, "分 ->", g)
}
}
}
单元11 · 并发编程
goroutine、channel、sync.WaitGroup
- goroutine:go 关键字启动轻量级并发任务。
- channel:make(chan T) 创建;<- 发送/接收;默认无缓冲需配对。
- WaitGroup:Add/Done/Wait 等待一组 goroutine 完成。
实训11.1 启动 goroutine
启动两个 goroutine 分别输出 1-5 和 A-E,用 fmt.Scanln 或等待防止主程序提前退出。
go 关键字启动并发任务;主函数结束时所有 goroutine 终止,需要等待。
package main
import "fmt"
func printNums() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
}
}
func printLetters() {
for _, c := range []string{"A", "B", "C", "D", "E"} {
fmt.Println(c)
}
}
func main() {
go printNums()
go printLetters()
fmt.Scanln()
}
实训11.2 channel 传递数据
创建一个 int 类型 channel,goroutine 发送数字 42,主函数接收并输出。
make(chan int) 创建通道;ch <- v 发送,v := <-ch 接收;无缓冲通道需要配对收发。
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println("收到:", value)
}
实训11.3 WaitGroup 等待并发完成
启动 3 个 goroutine 输出不同消息,用 sync.WaitGroup 等待全部完成。
wg.Add(n)、wg.Done()、wg.Wait() 组合使用;Done 可用 defer 保证执行。
package main
import (
"fmt"
"sync"
)
func work(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("任务", id, "完成")
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go work(i, &wg)
}
wg.Wait()
fmt.Println("所有任务完成")
}
实训11.4 并发求和与 channel 汇总
把 1-10 的求和拆成两个 goroutine(1-5、6-10),结果通过 channel 汇总。
每个 goroutine 算一段并把结果发到 channel,主函数接收两次求和。
package main
import "fmt"
func sumRange(start, end int, ch chan int) {
s := 0
for i := start; i <= end; i++ {
s += i
}
ch <- s
}
func main() {
ch := make(chan int)
go sumRange(1, 5, ch)
go sumRange(6, 10, ch)
part1 := <-ch
part2 := <-ch
fmt.Println("1-10 的总和:", part1+part2)
}
单元12 · 综合项目实训
综合运用所学知识完成项目
- 综合应用:结构体、切片、map、函数、错误处理组合使用。
- 输出格式化:fmt.Printf 的 \t 制表符、%.1f 保留小数。
实训12.1 学生成绩管理系统
用结构体和 map 实现简易学生成绩管理:录入 3 名学生(姓名、语文、数学),计算平均分并输出成绩单。
定义 Student 结构体保存成绩;用切片存储;遍历计算平均分并格式化输出。
package main
import "fmt"
type Student struct {
Name string
Chinese float64
Math float64
}
func (s Student) Average() float64 {
return (s.Chinese + s.Math) / 2
}
func main() {
students := []Student{
{Name: "张三", Chinese: 90, Math: 85},
{Name: "李四", Chinese: 78, Math: 92},
{Name: "王五", Chinese: 88, Math: 76},
}
fmt.Println("姓名 语文 数学 平均")
for _, s := range students {
fmt.Printf("%s %.1f %.1f %.1f\n", s.Name, s.Chinese, s.Math, s.Average())
}
}
实训12.2 单词频率统计
给定一段文本(以字符串数组模拟),统计每个单词出现的次数并输出出现次数最高的单词。
用 map[string]int 统计词频;遍历 map 找最大次数;strings.Fields 拆分文本。
package main
import (
"fmt"
"strings"
)
func main() {
text := "go is simple go is fast go is fun"
words := strings.Fields(text)
freq := make(map[string]int)
for _, w := range words {
freq[w]++
}
maxWord, maxCount := "", 0
for w, c := range freq {
if c > maxCount {
maxWord, maxCount = w, c
}
}
fmt.Println("词频统计:", freq)
fmt.Println("出现最多的词:", maxWord, ",次数:", maxCount)
}
实训12.3 命令行简易计算器
实现一个支持加、减、乘、除的简易计算器:输入操作数和运算符(模拟输入),输出结果。
用 fmt.Scan 读取输入,switch 判断运算符执行计算;除数为 0 时输出错误提示。
package main
import "fmt"
func main() {
var a, b float64
var op string
fmt.Print("输入第一个数:")
fmt.Scan(&a)
fmt.Print("输入运算符(+ - * /):")
fmt.Scan(&op)
fmt.Print("输入第二个数:")
fmt.Scan(&b)
switch op {
case "+":
fmt.Printf("结果:%.2f\n", a+b)
case "-":
fmt.Printf("结果:%.2f\n", a-b)
case "*":
fmt.Printf("结果:%.2f\n", a*b)
case "/":
if b == 0 {
fmt.Println("错误:除数不能为 0")
} else {
fmt.Printf("结果:%.2f\n", a/b)
}
default:
fmt.Println("无效运算符")
}
}