Menu
Coddy logo textTech

구조체 임베딩 기초

Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 107개 중 35번째.

구조체 임베딩(Struct embedding)은 하나의 구조체 타입을 다른 구조체 타입 안에 포함하는 Go의 메커니즘입니다. 필드 이름을 사용하는 대신 단순히 타입을 지정하며, Go는 임베딩된 구조체의 필드들을 외부 구조체로 승격(promote)시킵니다.

기본 구문은 다음과 같습니다:

type Address struct {
    City    string
    Country string
}

type Person struct {
    Name string
    Address  // 임베디드 - 필드 이름 없음
}

AddressPerson에 임베딩하면, 외부 구조체에서 임베딩된 필드에 직접 접근할 수 있습니다:

func main() {
    p := Person{
        Name: "Alice",
        Address: Address{
            City:    "London",
            Country: "UK",
        },
    }
    
    fmt.Println(p.City)     // London - 직접 접근
    fmt.Println(p.Country)  // UK - 직접 접근
    fmt.Println(p.Address.City)  // 이 방식도 가능합니다
}

p.Cityp.Address.City를 명시적으로 작성하지 않고도 어떻게 작동하는지 확인해 보세요. Go는 임베디드된 구조체의 필드를 자동으로 승격시켜, 마치 외부 구조체에 속한 것처럼 접근할 수 있게 합니다. 필요한 경우 임베디드된 타입 이름을 통해 여전히 접근할 수 있습니다.

이것은 내부 필드에 접근하기 위해 항상 필드 이름을 사용해야 하는 일반적인 중첩 구조체와 다릅니다. 임베딩은 관련 데이터의 논리적 그룹화를 유지하면서도 더 평평하고 편리한 API를 제공합니다.

challenge icon

챌린지

쉬움

구조체 임베딩(struct embedding)을 사용하여 깔끔하고 체계적인 데이터 모델을 만드는 차량 등록 시스템을 구축해 보겠습니다. 임베딩을 통해 모든 필드에 직접 접근할 수 있도록 하면서, 연락처 정보와 차량 상세 정보를 분리할 것입니다.

코드는 두 개의 파일로 구성됩니다:

  • vehicle.go: 임베딩을 통해 함께 작동하는 두 개의 구조체를 생성합니다:
    • OwnerNamePhone 필드(둘 다 문자열)를 가진 ContactInfo 구조체
    • ContactInfo를 임베딩하고(필드 이름 없이), 자체 필드인 Make, Model, Year를 추가한 Vehicle 구조체
    또한, 모든 차량 및 연락처 정보를 포함하는 형식화된 문자열을 반환하는 Summary라는 메서드를 Vehicle에 생성합니다.
  • main.go: 입력으로부터 차량 및 소유자 상세 정보를 읽고, ContactInfo가 임베딩된 Vehicle 인스턴스를 생성합니다. 그리고 임베딩된 필드에 직접 접근하는 방식과 임베딩된 타입 이름을 통해 접근하는 방식 두 가지를 모두 보여줍니다. 마지막에 차량 요약 정보를 출력합니다.

다음 입력값이 제공됩니다:

  • 1행: 소유자 이름
  • 2행: 전화번호
  • 3행: 차량 제조사
  • 4행: 차량 모델
  • 5행: 연식 (정수)

Summary 메서드는 다음 형식의 문자열을 반환해야 합니다:

[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]

메인 파일에서 필드 프로모션(field promotion)을 보여주기 위해 다음을 출력하세요:

  1. Vehicle에서 직접 접근한 소유자 이름 (예: v.OwnerName)
  2. 임베딩된 타입을 통해 접근한 전화번호 (예: v.ContactInfo.Phone)
  3. Summary 메서드에서 생성된 전체 요약 정보

예를 들어, Alice Smith, 555-1234, Toyota, Camry, 2023이 주어지면 출력은 다음과 같아야 합니다:

Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234

필드 프로모션을 통한 직접 접근과 임베딩된 타입 이름을 통한 명시적 접근이라는 두 가지 접근 패턴이 모두 작동하는 방식을 확인해 보세요. 이를 통해 임베딩된 데이터를 유연하게 다룰 수 있습니다.

치트 시트

구조체 임베딩(Struct embedding)을 사용하면 필드 이름을 지정하지 않고 한 구조체 타입을 다른 구조체 타입 안에 포함할 수 있습니다. 임베딩된 구조체의 필드는 외부 구조체로 승격(promote)되어 직접 접근할 수 있게 됩니다.

기본 문법

type Address struct {
    City    string
    Country string
}

type Person struct {
    Name string
    Address  // embedded - no field name
}

임베딩된 필드 접근하기

임베딩된 필드에 접근하는 방법은 두 가지가 있습니다:

p := Person{
    Name: "Alice",
    Address: Address{
        City:    "London",
        Country: "UK",
    },
}

// 직접 접근 (필드 승격)
fmt.Println(p.City)     // London

// 임베딩된 타입 이름을 통한 접근
fmt.Println(p.Address.City)  // London

Go는 임베딩된 구조체의 필드를 자동으로 승격시켜, 마치 외부 구조체에 속한 것처럼 직접 접근할 수 있게 해줍니다. 필요한 경우 임베딩된 타입 이름을 통해 접근할 수도 있습니다.

직접 해보기

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 소유자 이름 읽기
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)

	// 전화번호 읽기
	phone, _ := reader.ReadString('\n')
	phone = strings.TrimSpace(phone)

	// 차량 제조사 읽기
	make, _ := reader.ReadString('\n')
	make = strings.TrimSpace(make)

	// 차량 모델 읽기
	model, _ := reader.ReadString('\n')
	model = strings.TrimSpace(model)

	// 연식 읽기
	yearStr, _ := reader.ReadString('\n')
	yearStr = strings.TrimSpace(yearStr)
	year, _ := strconv.Atoi(yearStr)

	// TODO: ContactInfo가 임베디드된 Vehicle 인스턴스 생성
	// 위의 입력에서 읽은 값들을 사용하세요

	// TODO: Vehicle에서 직접 접근한 소유자 이름 출력 (필드 프로모션)
	// 예시: fmt.Println(v.OwnerName)

	// TODO: 임베디드된 타입 이름을 통해 접근한 전화번호 출력
	// 예시: fmt.Println(v.ContactInfo.Phone)

	// TODO: Summary 메서드를 사용하여 전체 요약 출력
	// 예시: fmt.Println(v.Summary())

	// 솔루션을 구현한 후 이 라인들을 제거하세요
	_ = ownerName
	_ = phone
	_ = make
	_ = model
	_ = year
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨