結構體定義#

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
}

嵌入會把內部型別的方法「提升」到外部型別,可以直接呼叫。