package main
import "fmt"
func main() {
// 指针基础
var x int = 10
var p *int = &x
fmt.Printf("x的值: %d, x的地址: %p\n", x, &x)
fmt.Printf("p存储的地址: %p, p指向的值: %d\n", p, *p)
*p = 20 // 修改x的值
fmt.Printf("修改后x的值: %d\n", x)
// new函数分配内存
ptr := new(int)
*ptr = 100
fmt.Printf("new分配的内存地址: %p, 值: %d\n", ptr, *ptr)
// 指针作为函数参数
changeValue(&x)
fmt.Printf("函数调用后x的值: %d\n", x)
}
func changeValue(p *int) {
*p = 50
}
package main
import "fmt"
// 结构体定义
type Person struct {
Name string
Age int
}
// 构造函数
func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
Age: age,
}
}
// 值接收者方法
func (p Person) SayHello() string {
return "Hello, " + p.Name
}
// 指针接收者方法
func (p *Person) SetAge(age int) {
p.Age = age
}
func (p *Person) HaveBirthday() {
p.Age++
fmt.Printf("%s 过生日了,现在 %d 岁\n", p.Name, p.Age)
}
func main() {
// 创建结构体实例
p1 := Person{Name: "张三", Age: 25}
fmt.Println(p1.SayHello())
// 使用构造函数
p2 := NewPerson("李四", 30)
fmt.Println(p2.SayHello())
// 使用指针方法修改值
p2.SetAge(32)
fmt.Printf("%s 现在 %d 岁\n", p2.Name, p2.Age)
// 调用修改状态的方法
p2.HaveBirthday()
}
package main
import (
"fmt"
"math"
)
// 接口定义
type Shape interface {
Area() float64
Perimeter() float64
}
// 实现接口 - 矩形
type Rectangle struct {
Width, Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}
// 实现接口 - 圆形
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}
// 实现接口 - 三角形
type Triangle struct {
Base, Height float64
}
func (t Triangle) Area() float64 {
return 0.5 * t.Base * t.Height
}
func (t Triangle) Perimeter() float64 {
// 假设是等腰三角形
side := math.Sqrt(t.Base*t.Base/4 + t.Height*t.Height)
return t.Base + 2*side
}
// 多态函数
func PrintShapeInfo(s Shape) {
fmt.Printf("形状面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
func main() {
// 创建不同的形状
shapes := []Shape{
Rectangle{Width: 5, Height: 3},
Circle{Radius: 4},
Triangle{Base: 6, Height: 4},
}
// 多态调用
for i, shape := range shapes {
fmt.Printf("形状 %d: ", i+1)
PrintShapeInfo(shape)
}
// 类型断言
for _, shape := range shapes {
if rect, ok := shape.(Rectangle); ok {
fmt.Printf("矩形的宽: %.2f, 高: %.2f\n", rect.Width, rect.Height)
} else if circle, ok := shape.(Circle); ok {
fmt.Printf("圆形的半径: %.2f\n", circle.Radius)
}
}
}
package main
import (
"errors"
"fmt"
"strconv"
)
// 错误处理模式
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// 自定义错误类型
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
// 使用自定义错误的函数
func processValue(value int) (string, error) {
if value < 0 {
return "", MyError{Code: 400, Message: "值不能为负数"}
}
if value > 100 {
return "", MyError{Code: 413, Message: "值超出范围"}
}
return "处理成功: " + strconv.Itoa(value), nil
}
// 错误包装
func wrapError(value string) (int, error) {
num, err := strconv.Atoi(value)
if err != nil {
return 0, fmt.Errorf("转换失败: %w", err)
}
return num, nil
}
func main() {
// 测试基本错误处理
result, err := divide(10, 2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Println("结果:", result)
}
// 测试除零错误
_, err = divide(10, 0)
if err != nil {
fmt.Println("错误:", err)
}
// 测试自定义错误
values := []int{50, -5, 150}
for _, v := range values {
result, err := processValue(v)
if err != nil {
// 类型断言获取自定义错误
if myErr, ok := err.(MyError); ok {
fmt.Printf("自定义错误 - 代码: %d, 消息: %s\n", myErr.Code, myErr.Message)
} else {
fmt.Println("其他错误:", err)
}
} else {
fmt.Println(result)
}
}
// 测试错误包装
inputs := []string{"123", "abc", "45.6"}
for _, input := range inputs {
num, err := wrapError(input)
if err != nil {
fmt.Printf("输入 '%s' 转换失败: %v\n", input, err)
} else {
fmt.Printf("转换成功: %d\n", num)
}
}
}
package main
import (
"fmt"
"sync"
"time"
)
// goroutine示例
func sayHello(name string) {
for i := 0; i < 3; i++ {
fmt.Printf("你好, %s! (第%d次)\n", name, i+1)
time.Sleep(100 * time.Millisecond)
}
}
// channel通信示例
func channelDemo() {
fmt.Println("\n=== Channel通信示例 ===")
// 创建无缓冲channel
ch := make(chan int)
// 启动发送数据的goroutine
go func() {
for i := 0; i < 5; i++ {
fmt.Printf("发送: %d\n", i)
ch <- i
time.Sleep(200 * time.Millisecond)
}
close(ch) // 关闭channel
}()
// 接收数据
for value := range ch {
fmt.Printf("接收: %d\n", value)
}
}
// 缓冲channel示例
func bufferedChannelDemo() {
fmt.Println("\n=== 缓冲Channel示例 ===")
// 创建缓冲channel
ch := make(chan string, 3)
// 发送数据(不需要立即接收)
ch <- "消息1"
ch <- "消息2"
ch <- "消息3"
fmt.Println("已发送3条消息到缓冲channel")
// 接收数据
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
// 使用WaitGroup等待多个goroutine
func waitGroupDemo() {
fmt.Println("\n=== WaitGroup示例 ===")
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Goroutine %d 开始工作\n", id)
time.Sleep(time.Duration(id) * 200 * time.Millisecond)
fmt.Printf("Goroutine %d 完成工作\n", id)
}(i)
}
fmt.Println("等待所有goroutine完成...")
wg.Wait()
fmt.Println("所有goroutine已完成")
}
// select语句示例
func selectDemo() {
fmt.Println("\n=== Select语句示例 ===")
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "来自channel 1的消息"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "来自channel 2的消息"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
case <-time.After(3 * time.Second):
fmt.Println("超时!")
}
}
}
func main() {
// 启动多个goroutine
fmt.Println("=== Goroutine示例 ===")
go sayHello("张三")
go sayHello("李四")
// 等待一段时间让goroutine执行
time.Sleep(1 * time.Second)
// 演示channel通信
channelDemo()
// 演示缓冲channel
bufferedChannelDemo()
// 演示WaitGroup
waitGroupDemo()
// 演示select
selectDemo()
}
// go.mod文件示例
module github.com/username/project
go 1.19
require (
github.com/gin-gonic/gin v1.9.0
github.com/go-sql-driver/mysql v1.7.0
)
创建以下目录结构:
myproject/
├── go.mod
├── main.go
└── calculator/
├── add.go
└── subtract.go
calculator/add.go
package calculator
// Add 返回两个整数的和
func Add(a, b int) int {
return a + b
}
// AddMultiple 返回多个整数的和
func AddMultiple(nums ...int) int {
sum := 0
for _, num := range nums {
sum += num
}
return sum
}
calculator/subtract.go
package calculator
// Subtract 返回两个整数的差
func Subtract(a, b int) int {
return a - b
}
// SubtractMultiple 从第一个数中减去后续所有数
func SubtractMultiple(first int, nums ...int) int {
result := first
for _, num := range nums {
result -= num
}
return result
}
main.go
package main
import (
"fmt"
"github.com/username/project/calculator"
)
func main() {
// 使用自定义包中的函数
sum := calculator.Add(10, 20)
fmt.Printf("10 + 20 = %d\n", sum)
diff := calculator.Subtract(30, 15)
fmt.Printf("30 - 15 = %d\n", diff)
multipleSum := calculator.AddMultiple(1, 2, 3, 4, 5)
fmt.Printf("1 + 2 + 3 + 4 + 5 = %d\n", multipleSum)
multipleDiff := calculator.SubtractMultiple(100, 10, 20, 30)
fmt.Printf("100 - 10 - 20 - 30 = %d\n", multipleDiff)
}
包命名规范
可见性规则
依赖管理
# 初始化模块
go mod init github.com/username/project
# 添加依赖
go get github.com/gin-gonic/gin
# 整理依赖
go mod tidy
# 下载依赖
go mod download
# 查看依赖图
go mod graph
package main
import (
"fmt"
"sort"
)
// 学生结构体
type Student struct {
ID int
Name string
Grade int
Score float64
}
// 学生管理器
type StudentManager struct {
students []Student
nextID int
}
// 创建新的学生管理器
func NewStudentManager() *StudentManager {
return &StudentManager{
students: make([]Student, 0),
nextID: 1,
}
}
// 添加学生
func (sm *StudentManager) AddStudent(name string, grade int, score float64) error {
if name == "" {
return fmt.Errorf("学生姓名不能为空")
}
if grade < 1 || grade > 12 {
return fmt.Errorf("年级必须在1-12之间")
}
if score < 0 || score > 100 {
return fmt.Errorf("分数必须在0-100之间")
}
student := Student{
ID: sm.nextID,
Name: name,
Grade: grade,
Score: score,
}
sm.students = append(sm.students, student)
sm.nextID++
fmt.Printf("成功添加学生: %s (ID: %d)\n", name, student.ID)
return nil
}
// 根据ID查找学生
func (sm *StudentManager) FindStudentByID(id int) (Student, error) {
for _, student := range sm.students {
if student.ID == id {
return student, nil
}
}
return Student{}, fmt.Errorf("未找到ID为%d的学生", id)
}
// 更新学生信息
func (sm *StudentManager) UpdateStudent(id int, name string, grade int, score float64) error {
for i, student := range sm.students {
if student.ID == id {
if name != "" {
sm.students[i].Name = name
}
if grade >= 1 && grade <= 12 {
sm.students[i].Grade = grade
}
if score >= 0 && score <= 100 {
sm.students[i].Score = score
}
fmt.Printf("成功更新学生信息 (ID: %d)\n", id)
return nil
}
}
return fmt.Errorf("未找到ID为%d的学生", id)
}
// 删除学生
func (sm *StudentManager) DeleteStudent(id int) error {
for i, student := range sm.students {
if student.ID == id {
sm.students = append(sm.students[:i], sm.students[i+1:]...)
fmt.Printf("成功删除学生: %s (ID: %d)\n", student.Name, id)
return nil
}
}
return fmt.Errorf("未找到ID为%d的学生", id)
}
// 列出所有学生
func (sm *StudentManager) ListAllStudents() {
if len(sm.students) == 0 {
fmt.Println("暂无学生信息")
return
}
fmt.Println("所有学生信息:")
fmt.Println("ID\t姓名\t年级\t分数")
for _, student := range sm.students {
fmt.Printf("%d\t%s\t%d\t%.1f\n", student.ID, student.Name, student.Grade, student.Score)
}
}
// 按分数排序
func (sm *StudentManager) SortByScore(descending bool) {
sort.Slice(sm.students, func(i, j int) bool {
if descending {
return sm.students[i].Score > sm.students[j].Score
}
return sm.students[i].Score < sm.students[j].Score
})
}
// 计算平均分
func (sm *StudentManager) CalculateAverageScore() float64 {
if len(sm.students) == 0 {
return 0
}
total := 0.0
for _, student := range sm.students {
total += student.Score
}
return total / float64(len(sm.students))
}
// 按年级筛选
func (sm *StudentManager) FilterByGrade(grade int) []Student {
var filtered []Student
for _, student := range sm.students {
if student.Grade == grade {
filtered = append(filtered, student)
}
}
return filtered
}
func main() {
// 创建学生管理器
manager := NewStudentManager()
// 添加学生
manager.AddStudent("张三", 10, 85.5)
manager.AddStudent("李四", 11, 92.0)
manager.AddStudent("王五", 10, 78.5)
manager.AddStudent("赵六", 12, 95.5)
// 列出所有学生
manager.ListAllStudents()
// 查找学生
student, err := manager.FindStudentByID(2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("\n找到学生: %+v\n", student)
}
// 更新学生信息
err = manager.UpdateStudent(2, "李四华", 11, 93.5)
if err != nil {
fmt.Println("错误:", err)
}
// 按分数降序排序
manager.SortByScore(true)
fmt.Println("\n按分数降序排序:")
manager.ListAllStudents()
// 计算平均分
avg := manager.CalculateAverageScore()
fmt.Printf("\n所有学生的平均分: %.2f\n", avg)
// 按年级筛选
grade10Students := manager.FilterByGrade(10)
fmt.Println("\n10年级学生:")
for _, student := range grade10Students {
fmt.Printf("%s: %.1f分\n", student.Name, student.Score)
}
// 删除学生
err = manager.DeleteStudent(3)
if err != nil {
fmt.Println("错误:", err)
}
// 再次列出所有学生
fmt.Println("\n删除后的学生列表:")
manager.ListAllStudents()
}
package main
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"sync"
"time"
)
// 下载结果
type DownloadResult struct {
URL string
FilePath string
Error error
Size int64
Duration time.Duration
}
// 下载单个文件
func downloadFile(url, outputDir string, resultChan chan<- DownloadResult, wg *sync.WaitGroup) {
defer wg.Done()
startTime := time.Now()
// 获取文件名
fileName := filepath.Base(url)
if fileName == "." || fileName == "/" {
fileName = "downloaded_file"
}
filePath := filepath.Join(outputDir, fileName)
// 创建输出目录
if err := os.MkdirAll(outputDir, 0755); err != nil {
resultChan <- DownloadResult{
URL: url,
FilePath: "",
Error: fmt.Errorf("创建目录失败: %v", err),
Size: 0,
Duration: time.Since(startTime),
}
return
}
// 创建文件
file, err := os.Create(filePath)
if err != nil {
resultChan <- DownloadResult{
URL: url,
FilePath: "",
Error: fmt.Errorf("创建文件失败: %v", err),
Size: 0,
Duration: time.Since(startTime),
}
return
}
defer file.Close()
// 发送HTTP请求
resp, err := http.Get(url)
if err != nil {
resultChan <- DownloadResult{
URL: url,
FilePath: "",
Error: fmt.Errorf("下载失败: %v", err),
Size: 0,
Duration: time.Since(startTime),
}
return
}
defer resp.Body.Close()
// 检查响应状态
if resp.StatusCode != http.StatusOK {
resultChan <- DownloadResult{
URL: url,
FilePath: "",
Error: fmt.Errorf("服务器返回错误状态码: %d", resp.StatusCode),
Size: 0,
Duration: time.Since(startTime),
}
return
}
// 复制数据到文件
size, err := io.Copy(file, resp.Body)
if err != nil {
resultChan <- DownloadResult{
URL: url,
FilePath: "",
Error: fmt.Errorf("写入文件失败: %v", err),
Size: 0,
Duration: time.Since(startTime),
}
return
}
// 发送成功结果
resultChan <- DownloadResult{
URL: url,
FilePath: filePath,
Error: nil,
Size: size,
Duration: time.Since(startTime),
}
}
// 并发下载多个文件
func DownloadFiles(urls []string, outputDir string, maxConcurrency int) []DownloadResult {
// 限制并发数
semaphore := make(chan struct{}, maxConcurrency)
var wg sync.WaitGroup
resultChan := make(chan DownloadResult, len(urls))
// 启动下载goroutines
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
// 获取信号量
semaphore <- struct{}{}
defer func() { <-semaphore }()
downloadFile(url, outputDir, resultChan, &wg)
}(url)
}
// 等待所有下载完成
wg.Wait()
close(resultChan)
// 收集结果
var results []DownloadResult
for result := range resultChan {
results = append(results, result)
}
return results
}
// 显示下载进度
func showProgress(results []DownloadResult) {
var totalSize int64
var totalTime time.Duration
var successCount, failCount int
fmt.Println("\n=== 下载结果 ===")
for _, result := range results {
if result.Error != nil {
fmt.Printf("❌ %s: %v\n", result.URL, result.Error)
failCount++
} else {
fmt.Printf("✅ %s -> %s (%.2f KB, 耗时: %v)\n",
result.URL, result.FilePath, float64(result.Size)/1024, result.Duration)
totalSize += result.Size
totalTime += result.Duration
successCount++
}
}
fmt.Printf("\n总计: %d个文件, 成功: %d, 失败: %d\n", len(results), successCount, failCount)
fmt.Printf("总大小: %.2f KB, 总耗时: %v\n", float64(totalSize)/1024, totalTime)
if successCount > 0 {
avgSpeed := float64(totalSize) / totalTime.Seconds() / 1024
fmt.Printf("平均下载速度: %.2f KB/s\n", avgSpeed)
}
}
func main() {
// 示例URL列表(使用一些公开的测试文件)
urls := []string{
"https://httpbin.org/bytes/1024", // 1KB测试文件
"https://httpbin.org/bytes/5120", // 5KB测试文件
"https://httpbin.org/uuid", // UUID文本
"https://httpbin.org/ip", // IP地址
"https://httpbin.org/user-agent", // 用户代理
}
// 设置输出目录
outputDir := "./downloads"
// 设置最大并发数
maxConcurrency := 3
fmt.Printf("开始下载 %d 个文件,最大并发数: %d\n", len(urls), maxConcurrency)
// 开始下载
start := time.Now()
results := DownloadFiles(urls, outputDir, maxConcurrency)
totalDuration := time.Since(start)
// 显示结果
showProgress(results)
fmt.Printf("总下载时间: %v\n", totalDuration)
}
package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
"strings"
"sync"
"time"
)
// 客户端结构体
type Client struct {
conn net.Conn
name string
messages chan string
}
// 聊天室结构体
type ChatRoom struct {
clients map[*Client]bool
register chan *Client
unregister chan *Client
broadcast chan string
mutex sync.RWMutex
}
// 创建新的聊天室
func NewChatRoom() *ChatRoom {
return &ChatRoom{
clients: make(map[*Client]bool),
register: make(chan *Client),
unregister: make(chan *Client),
broadcast: make(chan string),
}
}
// 运行聊天室
func (cr *ChatRoom) Run() {
for {
select {
case client := <-cr.register:
cr.mutex.Lock()
cr.clients[client] = true
cr.mutex.Unlock()
fmt.Printf("客户端 %s 加入聊天室\n", client.name)
// 广播欢迎消息
cr.broadcast <- fmt.Sprintf("系统: %s 加入了聊天室", client.name)
case client := <-cr.unregister:
cr.mutex.Lock()
if _, ok := cr.clients[client]; ok {
delete(cr.clients, client)
close(client.messages)
fmt.Printf("客户端 %s 离开聊天室\n", client.name)
// 广播离开消息
cr.broadcast <- fmt.Sprintf("系统: %s 离开了聊天室", client.name)
}
cr.mutex.Unlock()
case message := <-cr.broadcast:
cr.mutex.RLock()
for client := range cr.clients {
select {
case client.messages <- message:
default:
// 如果客户端消息通道阻塞,跳过
close(client.messages)
delete(cr.clients, client)
}
}
cr.mutex.RUnlock()
}
}
}
// 处理客户端连接
func (cr *ChatRoom) handleClient(client *Client) {
// 发送欢迎消息
client.messages <- "欢迎来到聊天室!"
// 读取客户端消息
scanner := bufio.NewScanner(client.conn)
for scanner.Scan() {
message := scanner.Text()
if strings.TrimSpace(message) == "/quit" {
break
}
// 广播消息
cr.broadcast <- fmt.Sprintf("%s: %s", client.name, message)
}
// 客户端断开连接
cr.unregister <- client
client.conn.Close()
}
// 启动聊天服务器
func startServer(port string) {
chatRoom := NewChatRoom()
go chatRoom.Run()
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatalf("无法启动服务器: %v", err)
}
defer listener.Close()
fmt.Printf("聊天服务器启动,监听端口: %s\n", port)
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("接受连接错误: %v", err)
continue
}
// 创建新客户端
client := &Client{
conn: conn,
name: fmt.Sprintf("用户%d", time.Now().Unix()%1000),
messages: make(chan string, 10),
}
// 注册客户端
chatRoom.register <- client
// 处理客户端消息
go chatRoom.handleClient(client)
// 发送消息给客户端
go func(c *Client) {
for msg := range c.messages {
_, err := fmt.Fprintln(c.conn, msg)
if err != nil {
break
}
}
}(client)
}
}
// 聊天客户端
func startClient(serverAddr, name string) {
conn, err := net.Dial("tcp", serverAddr)
if err != nil {
log.Fatalf("无法连接到服务器: %v", err)
}
defer conn.Close()
// 发送客户端名称
fmt.Fprintf(conn, "%s\n", name)
// 启动接收消息的goroutine
go func() {
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
}()
// 读取用户输入并发送
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("输入消息 (/quit 退出): ")
text, err := reader.ReadString('\n')
if err != nil {
break
}
fmt.Fprintln(conn, text)
if strings.TrimSpace(text) == "/quit" {
break
}
}
}
func main() {
if len(os.Args) < 2 {
fmt.Println("使用方法:")
fmt.Println(" 服务器模式: go run chat.go server <port>")
fmt.Println(" 客户端模式: go run chat.go client <server:port> <name>")
return
}
mode := os.Args[1]
switch mode {
case "server":
if len(os.Args) < 3 {
fmt.Println("请指定端口号")
return
}
port := os.Args[2]
startServer(port)
case "client":
if len(os.Args) < 4 {
fmt.Println("请指定服务器地址和用户名")
return
}
serverAddr := os.Args[2]
name := os.Args[3]
startClient(serverAddr, name)
default:
fmt.Println("无效的模式,请使用 'server' 或 'client'")
}
}
A: 需要修改接收者状态时用指针,否则用值接收者
A: 缓冲channel可以存储多个值,非缓冲channel需要同步发送接收
A: 使用context控制goroutine生命周期,确保所有goroutine都能正常退出
完成本阶段学习后,进入第三阶段:实战模块开发