布吉網(wǎng)站設(shè)計(jì)快速優(yōu)化網(wǎng)站排名軟件
Go語言方法和接收器類型詳解
1. 方法接收器類型
1.1 值接收器
值接收器方法不會改變接收器的狀態(tài),因?yàn)镚o語言會在調(diào)用時(shí)復(fù)制接收器的值。因此,任何對接收器成員變量的修改都只會影響副本,而不會影響原始結(jié)構(gòu)體實(shí)例。
type Person struct {Name stringAge int
}// 值接收器方法
func (p Person) GetAge() int {return p.Age
}func TestValueReceiver(t *testing.T) {p := Person{Name: "Tom", Age: 20}if age := p.GetAge(); age != 20 {t.Errorf("Expected age 20, got %d", age)}// p的值在方法調(diào)用后不會改變
}
1.2 指針接收器
指針接收器允許直接操作接收器本身,這意味著可以安全地修改接收器的字段,并且這些更改會持續(xù)存在。
// 指針接收器方法
func (p *Person) SetAge(age int) {p.Age = age
}func TestPointerReceiver(t *testing.T) {p := &Person{Name: "Tom", Age: 20}p.SetAge(21)if p.Age != 21 {t.Errorf("Expected age 21, got %d", p.Age)}// p的值會被修改
}
2. 值類型和指針類型的方法調(diào)用
2.1 值類型調(diào)用指針接收器方法
func TestValueTypeCallPointerMethod(t *testing.T) {p := Person{Name: "Tom", Age: 20}p.SetAge(21) // Go 自動(dòng)轉(zhuǎn)換為 (&p).SetAge(21)if p.Age != 21 {t.Errorf("Expected age 21, got %d", p.Age)}
}
2.2 指針類型調(diào)用值接收器方法
func TestPointerTypeCallValueMethod(t *testing.T) {p := &Person{Name: "Tom", Age: 20}age := p.GetAge() // Go 自動(dòng)轉(zhuǎn)換為 (*p).GetAge()if age != 20 {t.Errorf("Expected age 20, got %d", age)}
}
3. 不可尋址的情況
3.1 Map值不可直接修改
func TestMapValueNotAddressable(t *testing.T) {people := make(map[string]Person)people["tom"] = Person{Name: "Tom", Age: 20}// 錯(cuò)誤做法// people["tom"].Age = 21// 正確的做法person := people["tom"]person.Age = 21people["tom"] = personif people["tom"].Age != 21 {t.Errorf("Expected age 21, got %d", people["tom"].Age)}
}
3.2 臨時(shí)值不可尋址
func TestTemporaryValueNotAddressable(t *testing.T) {// 以下代碼會編譯錯(cuò)誤// Person{Name: "Tom", Age: 20}.SetAge(21)// 可以調(diào)用值接收器方法age := Person{Name: "Tom", Age: 20}.GetAge()if age != 20 {t.Errorf("Expected age 20, got %d", age)}
}
3.3 字面量不可尋址
func TestLiteralNotAddressable(t *testing.T) {// 以下代碼會編譯錯(cuò)誤// (&struct{ name string }{"tom"}).name = "jerry"// 正確的做法是先賦值給變量p := Person{Name: "Tom", Age: 20}p.SetAge(21)if p.Age != 21 {t.Errorf("Expected age 21, got %d", p.Age)}
}
3.4 Map值是指針類型的情況
func TestMapWithPointerValues(t *testing.T) {// 創(chuàng)建一個(gè)字符串到 *Person 的映射people := make(map[string]*Person)// 添加一個(gè)新的 Person 到映射中people["tom"] = &Person{Name: "Tom", Age: 20}// 直接修改 tom 的年齡people["tom"].Age = 21if people["tom"].Age != 21 {t.Errorf("Expected age 21, got %d", people["tom"].Age)}
}
4. Map值的正確修改方式
- 獲取值的副本
- 修改副本
- 將修改后的副本存回map
5. 方法調(diào)用的自動(dòng)轉(zhuǎn)換
5.1 值到指針的自動(dòng)轉(zhuǎn)換
- Go編譯器自動(dòng)處理從值到指針的轉(zhuǎn)換
- 允許值類型調(diào)用指針接收器方法
5.2 指針到值的自動(dòng)轉(zhuǎn)換
- Go編譯器自動(dòng)處理從指針到值的轉(zhuǎn)換
- 允許指針類型調(diào)用值接收器方法
注意事項(xiàng)
-
選擇接收器類型時(shí)考慮:
- 是否需要修改接收器狀態(tài)
- 性能考慮
- 接口實(shí)現(xiàn)要求
-
處理不可尋址情況:
- 使用中間變量
- 正確處理map值的修改
- 注意指針類型的使用
-
使用map存儲指針時(shí):
- 可以直接修改指針指向的對象
- 確保指針正確初始化
- 考慮并發(fā)安全問題