/* 05-methods.go - Go 语言方法详解 学习目标: 1. 理解方法与函数的区别 2. 掌握方法的定义和调用 3. 学会值接收者和指针接收者的使用 4. 了解方法集的概念 5. 掌握方法的实际应用 知识点: - 方法定义语法 - 值接收者 vs 指针接收者 - 方法集和接口实现 - 方法的继承和组合 - 方法的实际应用场景 */ package main import ( "fmt" ) func main() { fmt.Println("=== Go 语言方法详解 ===\n") // 演示基本方法定义和调用 demonstrateBasicMethods() // 演示值接收者和指针接收者 demonstrateReceiverTypes() // 演示方法集和接口实现 demonstrateMethodSets() // 演示方法的继承和组合 demonstrateMethodComposition() // 演示方法的实际应用 demonstratePracticalApplications() // 演示方法的高级用法 demonstrateAdvancedMethodUsage() } // demonstrateBasicMethods 演示基本方法定义和调用 func demonstrateBasicMethods() { fmt.Println("1. 基本方法定义和调用:") // 创建结构体实例 fmt.Printf(" 创建和使用基本方法:\n") rect := Rectangle{Width: 10, Height: 5} fmt.Printf(" 矩形: %+v\n", rect) fmt.Printf(" 面积: %.2f\n", rect.Area()) fmt.Printf(" 周长: %.2f\n", rect.Perimeter()) // 方法链调用 fmt.Printf(" 方法链调用:\n") rect.SetWidth(8).SetHeight(6) fmt.Printf(" 修改后的矩形: %+v\n", rect) fmt.Printf(" 新面积: %.2f\n", rect.Area()) // 不同类型的方法 fmt.Printf(" 不同类型的方法:\n") circle := Circle{Radius: 3} fmt.Printf(" 圆形: %+v\n", circle) fmt.Printf(" 面积: %.2f\n", circle.Area()) fmt.Printf(" 周长: %.2f\n", circle.Circumference()) // 基本类型的方法 fmt.Printf(" 基本类型的方法:\n") var temp Temperature = 25.5 fmt.Printf(" 温度: %.1f°C\n", temp) fmt.Printf(" 华氏度: %.1f°F\n", temp.ToFahrenheit()) fmt.Printf(" 开尔文: %.1f K\n", temp.ToKelvin()) fmt.Println() }// demonstr ateReceiverTypes 演示值接收者和指针接收者 func demonstrateReceiverTypes() { fmt.Println("2. 值接收者和指针接收者:") // 值接收者示例 fmt.Printf(" 值接收者示例:\n") counter1 := Counter{Value: 0} fmt.Printf(" 初始计数器: %+v\n", counter1) // 值接收者方法不会修改原始值 counter1.IncrementByValue() fmt.Printf(" 值接收者增加后: %+v\n", counter1) // 值不变 // 指针接收者示例 fmt.Printf(" 指针接收者示例:\n") counter2 := Counter{Value: 0} fmt.Printf(" 初始计数器: %+v\n", counter2) // 指针接收者方法会修改原始值 counter2.IncrementByPointer() fmt.Printf(" 指针接收者增加后: %+v\n", counter2) // 值改变 // 方法调用的自动转换 fmt.Printf(" 方法调用的自动转换:\n") counter3 := Counter{Value: 10} counterPtr := &counter3 // 值类型可以调用指针接收者方法(自动取地址) counter3.IncrementByPointer() fmt.Printf(" 值类型调用指针方法: %+v\n", counter3) // 指针类型可以调用值接收者方法(自动解引用) result := counterPtr.GetValueCopy() fmt.Printf(" 指针类型调用值方法: %d\n", result) // 大结构体的性能考虑 fmt.Printf(" 大结构体的性能考虑:\n") largeStruct := LargeStruct{} for i := 0; i < 1000; i++ { largeStruct.Data[i] = i } // 值接收者会拷贝整个结构体 start := time.Now() largeStruct.ProcessByValue() valueTime := time.Since(start) // 指针接收者只传递指针 start = time.Now() largeStruct.ProcessByPointer() pointerTime := time.Since(start) fmt.Printf(" 值接收者耗时: %v\n", valueTime) fmt.Printf(" 指针接收者耗时: %v\n", pointerTime) fmt.Println() } // demonstrateMethodSets 演示方法集和接口实现 func demonstrateMethodSets() { fmt.Println("3. 方法集和接口实现:") // 接口实现 fmt.Printf(" 接口实现:\n") var shapes []Shape shapes = append(shapes, Rectangle{Width: 4, Height: 3}) shapes = append(shapes, Circle{Radius: 2}) shapes = append(shapes, Triangle{Base: 6, Height: 4}) totalArea := 0.0 for i, shape := range shapes { area := shape.Area() fmt.Printf(" 形状 %d 面积: %.2f\n", i+1, area) totalArea += area } fmt.Printf(" 总面积: %.2f\n", totalArea) // 方法集的规则 fmt.Printf(" 方法集的规则:\n") // 值类型的方法集 var drawable1 Drawable = Rectangle{Width: 5, Height: 3} drawable1.Draw() // 指针类型的方法集 rect := Rectangle{Width: 5, Height: 3} var drawable2 Drawable = &rect drawable2.Draw() // 可修改接口 fmt.Printf(" 可修改接口:\n") var modifiable Modifiable = &rect fmt.Printf(" 修改前: %+v\n", rect) modifiable.Modify() fmt.Printf(" 修改后: %+v\n", rect) // 注意:值类型不能实现需要指针接收者的接口 // var modifiable2 Modifiable = rect // 编译错误 fmt.Println() } // demonstrateMethodComposition 演示方法的继承和组合 func demonstrateMethodComposition() { fmt.Println("4. 方法的继承和组合:") // 结构体嵌入 fmt.Printf(" 结构体嵌入:\n") person := Person{ Name: "Alice", Age: 30, } employee := Employee{ Person: person, JobTitle: "软件工程师", Salary: 80000, } // 可以直接调用嵌入类型的方法 fmt.Printf(" 员工信息: %s\n", employee.GetInfo()) fmt.Printf(" 员工详情: %s\n", employee.GetDetails()) // 匿名嵌入 fmt.Printf(" 匿名嵌入:\n") manager := Manager{ Person: Person{ Name: "Bob", Age: 35, }, Department: "技术部", TeamSize: 10, } // 直接访问嵌入类型的方法和字段 fmt.Printf(" 经理姓名: %s\n", manager.Name) // 直接访问嵌入字段 fmt.Printf(" 经理信息: %s\n", manager.GetInfo()) // 直接调用嵌入方法 fmt.Printf(" 管理信息: %s\n", manager.Manage()) // 方法重写 fmt.Printf(" 方法重写:\n") student := Student{ Person: Person{ Name: "Charlie", Age: 20, }, School: "清华大学", Grade: "大三", } // Student 重写了 GetInfo 方法 fmt.Printf(" 学生信息: %s\n", student.GetInfo()) // 仍然可以访问原始方法 fmt.Printf(" 基础信息: %s\n", student.Person.GetInfo()) fmt.Println() }// dem onstratePracticalApplications 演示方法的实际应用 func demonstratePracticalApplications() { fmt.Println("5. 方法的实际应用:") // 应用1: 银行账户管理 fmt.Printf(" 应用1 - 银行账户管理:\n") account := BankAccount{ AccountNumber: "123456789", Balance: 1000.0, Owner: "Alice", } fmt.Printf(" 初始账户: %s\n", account.GetInfo()) account.Deposit(500.0) fmt.Printf(" 存款后: %s\n", account.GetInfo()) success := account.Withdraw(200.0) fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance) success = account.Withdraw(2000.0) fmt.Printf(" 取款成功: %t, 余额: %.2f\n", success, account.Balance) // 应用2: 购物车系统 fmt.Printf(" 应用2 - 购物车系统:\n") cart := ShoppingCart{} cart.AddItem("笔记本电脑", 5999.99, 1) cart.AddItem("鼠标", 99.99, 2) cart.AddItem("键盘", 299.99, 1) fmt.Printf(" 购物车内容:\n") cart.DisplayItems() fmt.Printf(" 总价: %.2f\n", cart.GetTotal()) cart.RemoveItem("鼠标") fmt.Printf(" 移除鼠标后总价: %.2f\n", cart.GetTotal()) // 应用3: 日志记录器 fmt.Printf(" 应用3 - 日志记录器:\n") logger := Logger{Level: "INFO"} logger.Info("应用程序启动") logger.Warning("配置文件使用默认值") logger.Error("数据库连接失败") logger.Debug("调试信息") // 不会显示,因为级别是 INFO logger.SetLevel("DEBUG") logger.Debug("现在可以看到调试信息了") // 应用4: 配置管理器 fmt.Printf(" 应用4 - 配置管理器:\n") config := Config{ settings: make(map[string]string), } config.Set("database.host", "localhost") config.Set("database.port", "5432") config.Set("app.debug", "true") fmt.Printf(" 数据库主机: %s\n", config.Get("database.host")) fmt.Printf(" 应用调试: %s\n", config.Get("app.debug")) fmt.Printf(" 不存在的配置: %s\n", config.Get("nonexistent")) fmt.Printf(" 所有配置:\n") config.DisplayAll() fmt.Println() } // demonstrateAdvancedMethodUsage 演示方法的高级用法 func demonstrateAdvancedMethodUsage() { fmt.Println("6. 方法的高级用法:") // 高级用法1: 方法表达式 fmt.Printf(" 高级用法1 - 方法表达式:\n") rect := Rectangle{Width: 4, Height: 3} // 方法表达式:将方法转换为函数 areaFunc := Rectangle.Area perimeterFunc := Rectangle.Perimeter fmt.Printf(" 使用方法表达式计算面积: %.2f\n", areaFunc(rect)) fmt.Printf(" 使用方法表达式计算周长: %.2f\n", perimeterFunc(rect)) // 高级用法2: 方法值 fmt.Printf(" 高级用法2 - 方法值:\n") // 方法值:绑定到特定实例的方法 rectAreaMethod := rect.Area rectPerimeterMethod := rect.Perimeter fmt.Printf(" 使用方法值计算面积: %.2f\n", rectAreaMethod()) fmt.Printf(" 使用方法值计算周长: %.2f\n", rectPerimeterMethod()) // 高级用法3: 接口组合 fmt.Printf(" 高级用法3 - 接口组合:\n") var readWriter ReadWriter = &File{Name: "test.txt"} data := []byte("Hello, World!") readWriter.Write(data) buffer := make([]byte, 20) n := readWriter.Read(buffer) fmt.Printf(" 读取到 %d 字节: %s\n", n, string(buffer[:n])) // 高级用法4: 类型断言和方法调用 fmt.Printf(" 高级用法4 - 类型断言和方法调用:\n") var shape Shape = Circle{Radius: 5} // 类型断言获取具体类型 if circle, ok := shape.(Circle); ok { fmt.Printf(" 圆的半径: %.2f\n", circle.Radius) fmt.Printf(" 圆的周长: %.2f\n", circle.Circumference()) } // 高级用法5: 方法集的动态调用 fmt.Printf(" 高级用法5 - 方法集的动态调用:\n") calculator := Calculator{} operations := []struct { name string method func(float64, float64) float64 }{ {"加法", calculator.Add}, {"减法", calculator.Subtract}, {"乘法", calculator.Multiply}, {"除法", calculator.Divide}, } a, b := 10.0, 3.0 for _, op := range operations { result := op.method(a, b) fmt.Printf(" %.1f %s %.1f = %.2f\n", a, op.name, b, result) } // 高级用法6: 链式方法调用 fmt.Printf(" 高级用法6 - 链式方法调用:\n") builder := NewStringBuilder() result := builder. Append("Hello"). Append(" "). Append("World"). Append("!"). ToUpper(). Build() fmt.Printf(" 构建结果: %s\n", result) fmt.Println() }// = ========= 类型和方法定义 ========== // 基本结构体和方法 type Rectangle struct { Width float64 Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) } // 指针接收者方法,支持方法链 func (r *Rectangle) SetWidth(width float64) *Rectangle { r.Width = width return r } func (r *Rectangle) SetHeight(height float64) *Rectangle { r.Height = height return r } func (r Rectangle) Draw() { fmt.Printf(" 绘制矩形: %.1f x %.1f\n", r.Width, r.Height) } func (r *Rectangle) Modify() { r.Width *= 1.1 r.Height *= 1.1 fmt.Printf(" 矩形已放大 10%%\n") } // 圆形结构体和方法 type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func (c Circle) Circumference() float64 { return 2 * math.Pi * c.Radius } func (c Circle) Draw() { fmt.Printf(" 绘制圆形: 半径 %.1f\n", c.Radius) } // 三角形结构体和方法 type Triangle struct { Base float64 Height float64 } func (t Triangle) Area() float64 { return 0.5 * t.Base * t.Height } func (t Triangle) Draw() { fmt.Printf(" 绘制三角形: 底边 %.1f, 高 %.1f\n", t.Base, t.Height) } // 基本类型的方法 type Temperature float64 func (t Temperature) ToFahrenheit() float64 { return float64(t)*9/5 + 32 } func (t Temperature) ToKelvin() float64 { return float64(t) + 273.15 } // 值接收者 vs 指针接收者示例 type Counter struct { Value int } // 值接收者:不会修改原始值 func (c Counter) IncrementByValue() { c.Value++ fmt.Printf(" 值接收者内部: %d\n", c.Value) } // 指针接收者:会修改原始值 func (c *Counter) IncrementByPointer() { c.Value++ fmt.Printf(" 指针接收者内部: %d\n", c.Value) } func (c Counter) GetValueCopy() int { return c.Value } // 大结构体性能测试 type LargeStruct struct { Data [1000]int } func (ls LargeStruct) ProcessByValue() { // 值接收者会拷贝整个结构体 sum := 0 for _, v := range ls.Data { sum += v } } func (ls *LargeStruct) ProcessByPointer() { // 指针接收者只传递指针 sum := 0 for _, v := range ls.Data { sum += v } } // 接口定义 type Shape interface { Area() float64 } type Drawable interface { Draw() } type Modifiable interface { Modify() } // 组合接口 type ReadWriter interface { Reader Writer } type Reader interface { Read([]byte) int } type Writer interface { Write([]byte) int } // 文件类型实现 ReadWriter 接口 type File struct { Name string data []byte } func (f *File) Read(buffer []byte) int { n := copy(buffer, f.data) return n } func (f *File) Write(data []byte) int { f.data = append(f.data, data...) return len(data) } // 结构体嵌入示例 type Person struct { Name string Age int } func (p Person) GetInfo() string { return fmt.Sprintf("%s (%d岁)", p.Name, p.Age) } type Employee struct { Person // 具名嵌入 JobTitle string Salary float64 } func (e Employee) GetDetails() string { return fmt.Sprintf("%s - %s, 薪资: %.0f", e.GetInfo(), e.JobTitle, e.Salary) } // 匿名嵌入 type Manager struct { Person // 匿名嵌入 Department string TeamSize int } func (m Manager) Manage() string { return fmt.Sprintf("管理 %s,团队规模: %d人", m.Department, m.TeamSize) } // 方法重写示例 type Student struct { Person School string Grade string } // 重写 Person 的 GetInfo 方法 func (s Student) GetInfo() string { return fmt.Sprintf("%s (%d岁) - %s %s", s.Name, s.Age, s.School, s.Grade) }// 实际应用 示例 // 银行账户 type BankAccount struct { AccountNumber string Balance float64 Owner string } func (ba *BankAccount) Deposit(amount float64) { if amount > 0 { ba.Balance += amount fmt.Printf(" 存款 %.2f,当前余额: %.2f\n", amount, ba.Balance) } } func (ba *BankAccount) Withdraw(amount float64) bool { if amount > 0 && amount <= ba.Balance { ba.Balance -= amount fmt.Printf(" 取款 %.2f,当前余额: %.2f\n", amount, ba.Balance) return true } fmt.Printf(" 取款失败:余额不足或金额无效\n") return false } func (ba BankAccount) GetInfo() string { return fmt.Sprintf("账户: %s, 户主: %s, 余额: %.2f", ba.AccountNumber, ba.Owner, ba.Balance) } // 购物车系统 type CartItem struct { Name string Price float64 Quantity int } type ShoppingCart struct { Items []CartItem } func (sc *ShoppingCart) AddItem(name string, price float64, quantity int) { // 检查是否已存在该商品 for i := range sc.Items { if sc.Items[i].Name == name { sc.Items[i].Quantity += quantity return } } // 添加新商品 sc.Items = append(sc.Items, CartItem{ Name: name, Price: price, Quantity: quantity, }) } func (sc *ShoppingCart) RemoveItem(name string) { for i, item := range sc.Items { if item.Name == name { sc.Items = append(sc.Items[:i], sc.Items[i+1:]...) return } } } func (sc ShoppingCart) GetTotal() float64 { total := 0.0 for _, item := range sc.Items { total += item.Price * float64(item.Quantity) } return total } func (sc ShoppingCart) DisplayItems() { for _, item := range sc.Items { fmt.Printf(" %s: %.2f × %d = %.2f\n", item.Name, item.Price, item.Quantity, item.Price*float64(item.Quantity)) } } // 日志记录器 type Logger struct { Level string } func (l *Logger) SetLevel(level string) { l.Level = level } func (l Logger) shouldLog(level string) bool { levels := map[string]int{ "DEBUG": 0, "INFO": 1, "WARN": 2, "ERROR": 3, } currentLevel := levels[l.Level] messageLevel := levels[level] return messageLevel >= currentLevel } func (l Logger) log(level, message string) { if l.shouldLog(level) { timestamp := time.Now().Format("2006-01-02 15:04:05") fmt.Printf(" [%s] %s: %s\n", timestamp, level, message) } } func (l Logger) Debug(message string) { l.log("DEBUG", message) } func (l Logger) Info(message string) { l.log("INFO", message) } func (l Logger) Warning(message string) { l.log("WARN", message) } func (l Logger) Error(message string) { l.log("ERROR", message) } // 配置管理器 type Config struct { settings map[string]string } func (c *Config) Set(key, value string) { c.settings[key] = value } func (c Config) Get(key string) string { if value, exists := c.settings[key]; exists { return value } return "" } func (c Config) DisplayAll() { for key, value := range c.settings { fmt.Printf(" %s = %s\n", key, value) } } // 计算器 type Calculator struct{} func (calc Calculator) Add(a, b float64) float64 { return a + b } func (calc Calculator) Subtract(a, b float64) float64 { return a - b } func (calc Calculator) Multiply(a, b float64) float64 { return a * b } func (calc Calculator) Divide(a, b float64) float64 { if b != 0 { return a / b } return 0 } // 字符串构建器(链式调用) type StringBuilder struct { parts []string } func NewStringBuilder() *StringBuilder { return &StringBuilder{parts: make([]string, 0)} } func (sb *StringBuilder) Append(str string) *StringBuilder { sb.parts = append(sb.parts, str) return sb } func (sb *StringBuilder) ToUpper() *StringBuilder { for i, part := range sb.parts { sb.parts[i] = strings.ToUpper(part) } return sb } func (sb *StringBuilder) Build() string { return strings.Join(sb.parts, "") } /* 运行这个程序: go run 05-methods.go 学习要点: 1. 方法是与特定类型关联的函数 2. 方法定义语法:func (receiver Type) MethodName() ReturnType 3. 值接收者和指针接收者有不同的行为和用途 4. 方法集决定了类型可以实现哪些接口 5. 结构体嵌入可以实现方法的继承和组合 方法 vs 函数: 1. 方法有接收者,函数没有 2. 方法属于特定类型,函数是独立的 3. 方法可以访问接收者的字段和其他方法 4. 方法支持多态(通过接口) 接收者类型选择: 1. 值接收者: - 不需要修改接收者 - 接收者是小的结构体 - 接收者是基本类型、数组或小的结构体 2. 指针接收者: - 需要修改接收者 - 接收者是大的结构体(避免拷贝) - 接收者包含不能拷贝的字段(如 sync.Mutex) 方法集规则: 1. 值类型 T 的方法集:所有值接收者方法 2. 指针类型 *T 的方法集:所有值接收者和指针接收者方法 3. 接口实现需要考虑方法集的匹配 最佳实践: 1. 保持接收者类型的一致性 2. 优先使用指针接收者(除非有特殊原因) 3. 合理使用结构体嵌入实现代码复用 4. 设计清晰的接口和方法签名 5. 使用方法实现面向对象的设计模式 常见应用场景: 1. 数据封装和操作 2. 业务逻辑实现 3. 接口实现和多态 4. 链式调用和流畅接口 5. 状态管理 6. 配置和选项处理 高级特性: 1. 方法表达式和方法值 2. 接口组合 3. 类型断言 4. 动态方法调用 5. 链式方法调用 */