結構體定義#
type Person struct {
Name string
Age int
addr string // 私有欄位(小寫開頭)
}
// 建立實體
p1 := Person{Name: "Alice", Age: 30}
p2 := Person{"Bob", 25, "taipei"} // 按順序,需提供所有欄位
p3 := new(Person) // 回傳 *Person,零值初始化方法定義#
方法是與特定型別關聯的函式:
// 值接收者
func (p Person) Greet() string {
return "Hello, " + p.Name
}
// 指標接收者
func (p *Person) SetAge(age int) {
p.Age = age // 可以修改接收者
}
// 使用
person := Person{Name: "Alice", Age: 30}
fmt.Println(person.Greet()) // 值或指標都可呼叫
person.SetAge(31) // 自動取址
(&person).SetAge(32) // 等效選擇接收者型別:
- 需要修改接收者狀態 ➡️ 指標接收者
- 接收者是大型結構體 ➡️ 指標接收者(避免複製)
- 一致性:同一型別的方法應使用相同的接收者型別
結構體嵌入#
Go 用嵌入(Embedding)取代繼承:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "..."
}
type Dog struct {
Animal // 嵌入 Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!" // 覆寫方法
}
// 使用
dog := Dog{
Animal: Animal{Name: "Buddy"},
Breed: "Golden Retriever",
}
fmt.Println(dog.Name) // 直接存取嵌入欄位
fmt.Println(dog.Speak()) // Woof!嵌入與組合的差異
// 嵌入(Embedding)- 匿名欄位
type Manager struct {
Person // 可以直接呼叫 m.Name, m.Greet()
Team []Person
}
// 組合(Composition)- 具名欄位
type Manager struct {
Employee Person // 必須透過 m.Employee.Name, m.Employee.Greet()
Team []Person
}嵌入會把內部型別的方法「提升」到外部型別,可以直接呼叫。