프로그래밍백엔드 개발자

Go에서 구조체의 중첩(embedding structs)은 어떻게 작동합니까? embedding과 일반적인 구조체 포함은 어떤 차이가 있습니까? 어떤 세부 사항을 고려해야 합니까?

Hintsage AI 어시스턴트로 면접 통과

답변

Go에서 embedding(구조체 내 삽입)은 명시적 상속 없이 하나의 구조체를 다른 구조체에 삽입하여 구조체의 동작을 "상속하는" 메커니즘입니다. 삽입된 구조체는 새 구조체의 필드(익명의 필드)가 됩니다.

이때 모든 메서드가 삽입된 구조체의 메서드가 되어 마치 "상속된" 것처럼 동작합니다.

예제:

package main import "fmt" type Animal struct { Name string } func (a Animal) Speak() { fmt.Println("내 이름은", a.Name) } type Dog struct { Animal // embedding, 익명 필드 Breed string } func main() { d := Dog{ Animal: Animal{Name: "Rex"}, Breed: "Shepherd", } d.Speak() // 상속된 메서드! fmt.Println(d.Name) // 필드에 직접 접근 가능 }

embedding과 구조체를 이름 있는 필드로 일반적으로 포함시키는 것의 주요 차이점:

  • embedding 메서드와 필드는 새 구조체에서 직접 접근할 수 있습니다.
  • 일반적인 포함은 필드 이름을 통해 접근해야 합니다.

함정 질문

"삽입된 구조체와 외부 구조체가 동일한 이름의 필드를 가지고 있다면 어떤 필드가 사용되며 어떻게 접근합니까?"

많은 사람들은 "상위" 필드만 사용된다고 생각하지만, 실제로는 다릅니다:

  • 이름이 일치하면 외부 수준이 사용되며, 내부 구조체는 삽입된 구조체의 이름을 통해 접근할 수 있습니다.

예제:

type Base struct { Name string } type Child struct { Base // embedding Name string // 일치하는 필드 } c := Child{Base: Base{Name: "Base"}, Name: "Child"} fmt.Println(c.Name) // Child fmt.Println(c.Base.Name) // Base

주제에 대한 세부 사항을 모른 채 발생한 실제 오류 예


사례

프로젝트에서 표준 로깅 구조체를 삽입한 후 자식 타입에 필드 Logger를 정의했습니다. 그 결과, d.Logger.Info() 호출이 예상대로 작동하지 않았습니다. 왜냐하면 삽입된 필드에 대한 접근이 동일한 이름 사이에서 "사라졌기" 때문입니다.


사례

개발자가 자식 구조체에서 메서드를 재정의하려고 했지만 메서드는 "override"되지 않고 단지 새로운 메서드가 생성되며 부모 메서드는 여전히 Child.Base.Method()로 접근이 가능했습니다. 이로 인해 일부 코드가 "오래된" 메서드 버전을 사용하여 다른 로직을 기대했습니다.


사례

중첩 구조체를 가진 JSON 직렬화에서 예기치 않은 일이 발생했습니다. "삽입된" 구조체의 필드가 루트 객체에 나타났습니다. embedding이 marshaling에 미치는 영향을 모르는 바람에 구조체가 잘못 직렬화되어 API의 하위 호환성이 깨졌습니다.