Files
2025-08-24 01:01:26 +08:00

869 lines
20 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
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. 链式方法调用
*/