Go에서의 덕 타이핑
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 42번째.
덕 타이핑이라는 용어는 다음과 같은 말에서 유래했습니다. "오리처럼 걷고 오리처럼 꽥꽥거리면, 그것은 오리다." Go에서는 타입이 interface를 구현한다고 명시적으로 선언할 필요가 없다는 뜻입니다. 올바른 method만 가지고 있으면 됩니다.
이 인터페이스와 서로 완전히 관련이 없는 두 가지 타입을 살펴보세요:
type Quacker interface {
Quack() string
}
type Duck struct{}
func (d Duck) Quack() string { return "Quack!" }
type Robot struct{}
func (r Robot) Quack() string { return "Beep-quack!" }
Duck도 Robot도 정의 어디에서도 Quacker를 언급하지 않습니다. 하지만 둘 다 올바른 시그니처를 가진 Quack() method를 가지고 있기 때문에 interface를 만족합니다:
func MakeItQuack(q Quacker) {
fmt.Println(q.Quack())
}
func main() {
MakeItQuack(Duck{}) // 꽥!
MakeItQuack(Robot{}) // 삑-꽥!
}
이 암시적 충족은 강력합니다. 유형이 이미 존재한 후에 인터페이스를 정의할 수 있기 때문입니다. 외부 패키지의 유형과 일치하는 인터페이스를 해당 소스 코드를 수정하지 않고 만들 수 있습니다. 유형은 여러분의 인터페이스를 알 필요가 없습니다. 올바르게 동작하기만 하면 됩니다.
Go의 덕 타이핑은 컴파일 시점의 타입 안전성을 유지하면서 동적 언어의 유연성을 제공합니다. 컴파일러는 타입을 인터페이스 값으로 사용하도록 허용하기 전에 실제로 필요한 메서드를 갖추고 있는지 확인합니다.
챌린지
쉬움실제로 duck typing을 보여 주는 messaging system을 만들어 봅시다. 어떤 type도 명시적으로 implement한다고 선언하지 않아도 모두 공통 interface를 통해 message를 보낼 수 있도록, 서로 완전히 관련 없는 type을 만들 것입니다.
code를 세 개의 file에 나누어 구성합니다:
messengers.go: 우연히 동일한 동작을 공유하는 서로 관련 없는 세 개의 struct를 Create합니다:Phone과Numberfield. 이 type의SendMessage(text string) stringmethod는SMS to [Number]: [text]를 반환합니다.Computer와Emailfield. 이 type의SendMessage(text string) stringmethod는Email to [Email]: [text]를 반환합니다.Pigeon과Namefield. 이 type의SendMessage(text string) stringmethod는[Name] carries: [text]를 반환합니다.
interface도 언급하지 않는다는 점에 주목하세요. 단지 동일한 method signature를 우연히 가지고 있을 뿐입니다.sender.go:SendMessage(text string) stringmethod를 요구하는Messengerinterface를 Define합니다.Messenger의 slice와 message string을 받아 각 messenger에서SendMessage를 calling한 결과가 담긴 string slice를 반환하는Broadcast라는 function을 Create합니다.main.go: input에서 세부 정보를 읽고, 각 messenger type을 하나씩 Create한 다음, 이들을Messenger의 slice에 모아Broadcast를 사용하여 모든 messenger를 통해 message를 보냅니다. 각 결과를 자체 line에 출력합니다.
다음 input이 제공됩니다:
- Line 1: Phone number
- Line 2: Email address
- Line 3: Pigeon name
- Line 4: Broadcast할 message
예를 들어 555-1234, alice@mail.com, Winston, Hello World가 주어지면 output은 다음과 같아야 합니다:
SMS to 555-1234: Hello World
Email to alice@mail.com: Hello World
Winston carries: Hello World여기서 핵심 통찰은 Phone, Computer, Pigeon 사이에 공통점이 전혀 없다는 것입니다. 이들은 base type을 공유하지 않으며 Messenger를 명시적으로 implement하지도 않습니다. 그러나 모두 같은 방식으로 "quack"하기 때문에(일치하는 method를 가지고 있기 때문에) Go에서는 이들을 모두 Messenger value로 사용할 수 있습니다. 이것이 실제로 작동하는 duck typing입니다.
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 전화번호 읽기
scanner.Scan()
phoneNumber := scanner.Text()
// Read email address
scanner.Scan()
email := scanner.Text()
// 비둘기 이름 읽기
scanner.Scan()
pigeonName := scanner.Text()
// 방송할 메시지 읽기
scanner.Scan()
message := scanner.Text()
// TODO: 각 메신저 타입(Phone, Computer, Pigeon)을 하나씩 생성
// TODO: 모든 메신저를 Messenger 슬라이스에 수집
// TODO: Broadcast를 사용하여 모든 메신저를 통해 메시지 전송
// TODO: 각 결과를 별도의 줄에 출력
// 변수를 사용하기 위한 플레이스홀더 (구현 시 제거)
_ = phoneNumber
_ = email
_ = pigeonName
_ = message
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러