Skip to content
Search

Go:Embedding

lastmod 2025-11-19created 2025-11-193 edits

About

Embedding in Go means including another struct or interface inside a struct by its type name alone, without a field name.

First, let's look at the 'Composition' approach we usually know.

Composition

type Engine struct {
    Horsepower int
}
func (e *Engine) Start() {
    fmt.Println("엔진 시동!")
}

type Car struct {
    engineField Engine // 'engineField'라는 필드 이름을 명시
}

func main() {
    myCar := Car{}
    myCar.engineField.Start() // 필드 이름을 통해 메서드 호출
}

Embedding

type Engine struct {
    Horsepower int
}
func (e *Engine) Start() {
    fmt.Println("엔진 시동!")
}

type Car struct {
    Engine // 필드 이름 없이 타입 이름만 포함
}

func main() {
    myCar := Car{}
    myCar.Start() // Engine의 메서드를 Car가 직접 가진 것처럼 호출!
}

Promotion of methods and fields

The fields and methods of an embedded type can be accessed directly as if they were fields and methods of the outer struct, which maximizes code reuse.

package main

import "fmt"

type Person struct {
    Name string
}

func (p Person) Greet() {
    fmt.Printf("안녕하세요, 제 이름은 %s입니다.\n", p.Name)
}

// Person 구조체를 임베딩하는 Employee 구조체
type Employee struct {
    Person     // Person을 임베딩
    EmployeeID string
}

func main() {
    emp := Employee{
        Person:     Person{Name: "Royce"},
        EmployeeID: "KE-1234",
    }

    // 1. 필드 승격: emp.Person.Name 대신 emp.Name으로 바로 접근
    fmt.Println(emp.Name) // 출력: Royce

    // 2. 메서드 승격: emp.Person.Greet() 대신 emp.Greet()으로 바로 호출
    emp.Greet() // 출력: 안녕하세요, 제 이름은 Royce입니다.
}

Overriding? No, Method Shadowing!

What happens if the outer struct and the embedded struct have methods with the same name? In that case, the outer struct's method takes precedence. In other words, the outer method 'shadows' the inner method.

type Employee struct {
    Person
    EmployeeID string
}

// Employee에 Greet 메서드를 새로 정의
func (e Employee) Greet() {
    fmt.Printf("카카오엔터프라이즈 직원, ")
    // 만약 임베딩된 타입의 메서드를 호출하고 싶다면, 명시적으로 접근해야 합니다.
    e.Person.Greet() 
}

func main() {
    emp := Employee{ /* ... */ }
    emp.Greet()
    // 출력: 카카오엔터프라이즈 직원, 안녕하세요, 제 이름은 Royce입니다.
}

Calling emp.Greet() runs the Greet defined directly on Employee. This is the closest thing to method overriding in Go.

The most important difference: embedding is not inheritance

Embedding is convenient, but it is not inheritance. The biggest difference between the two lies in the is-a relationship versus the has-a relationship.

  • Inheritance (is-a relationship): A cat is an animal. A child class can be treated as the parent class type.
  • Embedding (has-a relationship): An Employee has a (has-a) Person. From the Go type system's point of view, an Employee is not a Person.

Here is code that proves this.

func SayHelloToPerson(p Person) {
    p.Greet()
}

func main() {
    emp := Employee{Person: {Name: "Royce"}}

    // SayHelloToPerson(emp) // 컴파일 에러!
    // 에러 메시지: cannot use emp (variable of type Employee) as Person value in argument to SayHelloToPerson

    // Employee는 Person이 아니므로, Person을 받는 함수에 직접 전달할 수 없습니다.
    // 명시적으로 Person 필드를 전달해야만 합니다.
    SayHelloToPerson(emp.Person) // OK!
}

The compiler clearly tells you that Employee is not of type Person. This is the decisive evidence of how Go avoids the complexity of 'inheritance' and prefers 'composition'.

See also

Favorite site

author Zer0 sitemap