메서드 프로모션
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 36번째.
struct 임베딩이 필드를 바깥쪽 struct로 승격하는 것처럼, Go는 임베드된 타입의 method도 승격합니다. 즉, 임베드된 struct에 정의된 method를 바깥쪽 struct에서 직접 호출할 수 있습니다.
type Engine struct {
Horsepower int
}
func (e Engine) Start() string {
return "Engine started"
}
type Car struct {
Model string
Engine // 임베디드
}
Car가 Engine을 임베드하므로 Start() 메서드는 자동으로 승격됩니다:
func main() {
c := Car{
Model: "Sedan",
Engine: Engine{Horsepower: 200},
}
fmt.Println(c.Start()) // 엔진 시작됨
fmt.Println(c.Engine.Start()) // 또한 작동함
}
이 승격은 interface에 중요한 결과를 가져옵니다. embedded type이 interface를 satisfies하면, 외부 타입도 자동으로 이를 satisfies합니다:
type Starter interface {
Start() string
}
func Ignite(s Starter) {
fmt.Println(s.Start())
}
func main() {
c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
Ignite(c) // Car는 Engine을 통해 Starter를 만족합니다
}
Car 타입은 Starter를 명시적으로 구현하지 않지만, 내장된 Engine에 필요한 method가 있으므로 인터페이스를 충족합니다. 이것이 Go가 전통적인 상속 없이 동작 재사용을实现하는 방식입니다.
챌린지
쉬움임베드된 타입의 method가 외부 타입으로 승격되는 방식과, 이를 통해 composition으로 interface를 만족할 수 있는 방식을 보여 주는 music player 시스템을 만들어 보겠습니다.
코드를 두 파일로 구성합니다:
audio.go: music player의 구성 요소를 만듭니다:AudioPlayerstruct에Brandfield(string)와[Brand] playing audio를 returns하는Play() stringmethod를 정의합니다.Playableinterface에Play() stringmethod를 requiring하도록 정의합니다.AudioPlayer를 embedded하는Modelfield가 있는Smartphonestruct를 정의합니다.AudioPlayer를 embedded하는Modelfield가 있는Tabletstruct를 정의합니다.
main.go: anyPlayable을 accepts하고Play()을 calling한 result를 returns하는StartPlayback이라는 function을 만듭니다. input에서 device 정보를 Read하고, Smartphone과 Tablet을 모두 Create한 다음, 두 타입 모두 자체적으로Play()를 명시적으로 구현하지 않았지만 embeddedAudioPlayer를 통해Playableinterface를 만족한다는 것을 보여 줍니다.
다음 input이 제공됩니다:
- Line 1: Smartphone model 이름
- Line 2: Smartphone audio brand
- Line 3: Tablet model 이름
- Line 4: Tablet audio brand
각 device에 대해 해당 device의 model을 출력한 후, 해당 device를 StartPlayback에 전달한 result를 출력합니다.
예를 들어 iPhone 15, Apple Audio, iPad Pro, Beats가 주어지면 output은 다음과 같아야 합니다:
iPhone 15
Apple Audio playing audio
iPad Pro
Beats playing audioAudioPlayer의 Play() method가 각 외부 타입으로 자동으로 승격되므로, 추가 code 없이 Playable interface를 만족하여 Smartphone과 Tablet 모두 StartPlayback에 전달할 수 있다는 점에 주목하세요.
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: 어떤 Playable이든 받아들이는 StartPlayback 함수를 생성하세요
// 그리고 Play()를 호출한 결과를 반환합니다
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 스마트폰 모델 읽기
scanner.Scan()
smartphoneModel := scanner.Text()
// 스마트폰 오디오 브랜드 읽기
scanner.Scan()
smartphoneBrand := scanner.Text()
// 태블릿 모델 읽기
scanner.Scan()
tabletModel := scanner.Text()
// 태블릿 오디오 브랜드 읽기
scanner.Scan()
tabletBrand := scanner.Text()
// TODO: 임베디드 AudioPlayer가 있는 Smartphone을 생성하세요
// TODO: 임베디드 AudioPlayer가 있는 Tablet을 생성하세요
// TODO: 스마트폰 모델을 출력한 다음, 스마트폰으로 StartPlayback을 호출하세요
// TODO: 태블릿 모델을 출력한 다음, 태블릿으로 StartPlayback을 호출하세요
_ = smartphoneModel
_ = smartphoneBrand
_ = tabletModel
_ = tabletBrand
fmt.Println("TODO: Complete the implementation")
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러