BudiBadu Logo

Samplebadu

Code with Example
BudiBadu Logo
Samplebadu

Go by Example: Embedded Fields

Go 1.23

Go uses struct embedding to achieve composition over inheritance. This example demonstrates how embedded fields work, method promotion, and how to access shadowed fields.

Code

package main

import "fmt"

// 1. Base Struct
type User struct {
    Name  string
    Email string
}

// Method on User
func (u *User) Notify() {
    fmt.Printf("Sending email to %s <%s>\n", u.Name, u.Email)
}

// 2. Embedding Struct
// Admin "is a" User (composition)
type Admin struct {
    User  // Embedded field (no name)
    Level string
}

func main() {
    // 3. Initialization
    // We must initialize the embedded struct explicitly.
    ad := Admin{
        User: User{
            Name:  "System Admin",
            Email: "[email protected]",
        },
        Level: "Superuser",
    }

    // 4. Field Promotion
    // We can access Name directly on Admin, even though it's in User.
    fmt.Println("Name:", ad.Name)
    fmt.Println("Level:", ad.Level)

    // 5. Method Promotion
    // Admin automatically gets the Notify method from User.
    ad.Notify()

    // 6. Accessing the embedded field directly
    // Useful if there's a name collision (shadowing).
    fmt.Println("Inner Email:", ad.User.Email)
}

Explanation

Go eschews traditional class-based inheritance in favor of composition via struct embedding, a powerful mechanism that allows a struct to include another struct as an anonymous field, thereby inheriting its fields and methods. When a type is embedded, its fields and methods are "promoted" to the outer struct, enabling direct access as if they were defined on the outer struct itself; this facilitates code reuse and modular design while maintaining a flat and transparent type hierarchy. This approach aligns with the "is-a" relationship concept but implements it through containment, giving developers the flexibility to compose complex behaviors from smaller, focused types without the fragility often associated with deep inheritance trees.

Method promotion is a key consequence of embedding, where methods defined on the inner type become part of the outer type's method set, allowing interfaces satisfied by the inner type to be automatically satisfied by the outer type as well. However, Go resolves naming conflicts through explicit rules: if the outer struct defines a field or method with the same name as one in the embedded struct, the outer one "shadows" the inner one. In such cases, the shadowed member remains accessible by explicitly referencing the embedded type's name, ensuring that ambiguity is resolved deterministically and that the developer retains full control over the struct's behavior.

  • Composition: Build complex types from simple ones.
  • Promotion: Inner fields/methods appear on the outer struct.
  • Shadowing: Outer fields override inner ones with same name.
  • Interfaces: Outer struct satisfies interfaces of embedded struct.

Code Breakdown

19
Embedding the 'User' struct. By listing the type 'User' without a field name, we create an embedded field. This tells Go to promote all fields and methods of 'User' to 'Admin'.
36
Field promotion in action. 'ad.Name' works even though 'Name' is actually inside 'ad.User'. Go automatically forwards the access to the embedded struct.
41
Method promotion. The 'Notify' method was defined on '*User', but we can call it on 'ad' (which is an 'Admin'). This allows 'Admin' to satisfy any interface that requires 'Notify'.
45
Explicit access. The embedded field is implicitly named after its type. So we can access 'ad.User' to get the inner struct. This is necessary if 'Admin' also had a field named 'Name' or 'Email'.