package main import "fmt" type Student struct { Name string Age int Score float64 } // 1. 普通函数:学生作为普通参数传入。 func describe(student Student) string { return fmt.Sprintf("%s,年龄:%d,成绩:%.1f", student.Name, student.Age, student.Score) } // 2. 方法:func 后面的 (student Student) 称为接收者。 // 值接收者接收 Student 值的副本,这个方法只读取字段。 func (student Student) Summary() string { return fmt.Sprintf("%s,年龄:%d,成绩:%.1f", student.Name, student.Age, student.Score) } // 3. 值接收者中修改整数,只修改副本,不改变原学生。 func (student Student) TryBirthday() { student.Age++ } // 4. 指针接收者可以通过指针修改原学生。 // 本方法约定允许 nil,返回 false 表示没有可修改的学生。 func (student *Student) Birthday() bool { if student == nil { return false } student.Age++ return true } // 5. 方法也能接收普通参数,并通过返回值报告是否成功。 func (student *Student) SetScore(score float64) bool { // 这种写法同时拒绝不在范围内的值和 NaN。 if student == nil || !(score >= 0 && score <= 100) { return false } student.Score = score return true } func main() { student := Student{Name: "小朱", Age: 20, Score: 85} fmt.Println("=== 普通函数与方法 ===") fmt.Println("普通函数:", describe(student)) fmt.Println("方法调用:", student.Summary()) fmt.Println("\n=== 值接收者 ===") student.TryBirthday() fmt.Printf("调用 TryBirthday 后,原年龄:%d\n", student.Age) fmt.Println("\n=== 指针接收者 ===") // student 是可以取地址的变量,Go 自动把调用理解为 (&student).Birthday()。 ok := student.Birthday() fmt.Printf("调用 Birthday 后,年龄:%d,成功:%t\n", student.Age, ok) fmt.Println("\n=== 方法参数与返回值 ===") ok = student.SetScore(95) fmt.Printf("设置 95 分:成功=%t,当前成绩=%.1f\n", ok, student.Score) ok = student.SetScore(120) fmt.Printf("设置 120 分:成功=%t,当前成绩=%.1f\n", ok, student.Score) fmt.Println("\n=== 通过指针调用方法 ===") pointer := &student // *Student 也可以调用值接收者的方法,前提是这里指针非 nil。 fmt.Println(pointer.Summary()) fmt.Println("\n=== nil 指针接收者 ===") var empty *Student fmt.Printf("nil 调用 Birthday:%t\n", empty.Birthday()) fmt.Printf("nil 调用 SetScore:%t\n", empty.SetScore(80)) // empty.Summary() 不能安全调用:值接收者需要取得 Student 值。 }