🔥 인터페이스는 암시적으로 구현된다

270자
4분

Go 언어에서는 인터페이스를 구현할 때 명시적인 선언이 필요하지 않습니다. 대신 해당 인터페이스의 메서드를 구현하기만 하면 암시적으로 그 인터페이스를 구현하게 됩니다. 이를 통해 인터페이스의 정의와 구현을 분리할 수 있으며, 구현체는 어떤 패키지에서든 미리 약속하지 않고 나타날 수 있습니다.

다음 예제 코드를 통해 이를 살펴보겠습니다:

go
package main
 
import "fmt"
 
type I interface {
	M()
}
 
type T struct {
	S string
}
 
// 이 메서드는 타입 T가 인터페이스 I를 구현한다는 것을 의미합니다.
// 하지만 우리는 명시적으로 선언할 필요가 없습니다.
func (t T) M() {
	fmt.Println(t.S)
}
 
func main() {
	var i I = T{"hello"}
	i.M()
}
 
go
package main
 
import "fmt"
 
type I interface {
	M()
}
 
type T struct {
	S string
}
 
// 이 메서드는 타입 T가 인터페이스 I를 구현한다는 것을 의미합니다.
// 하지만 우리는 명시적으로 선언할 필요가 없습니다.
func (t T) M() {
	fmt.Println(t.S)
}
 
func main() {
	var i I = T{"hello"}
	i.M()
}
 

위 코드에서는 I라는 인터페이스를 정의하고 있습니다. 이 인터페이스는 M()이라는 메서드를 가지고 있습니다.

go
type I interface {
	M()
}
 
go
type I interface {
	M()
}
 

그리고 T라는 구조체를 정의합니다. 이 구조체는 S라는 문자열 필드를 가지고 있습니다.

go
type T struct {
	S string
}
 
go
type T struct {
	S string
}
 

다음으로 T 타입에 대해 M() 메서드를 구현합니다. 이 메서드는 T 타입의 S 필드를 출력하는 역할을 합니다.

go
func (t T) M() {
	fmt.Println(t.S)
}
 
go
func (t T) M() {
	fmt.Println(t.S)
}
 

이 메서드를 구현함으로써 T 타입은 I 인터페이스를 암시적으로 구현하게 됩니다. 우리는 따로 "TI를 구현한다"는 것을 명시적으로 선언할 필요가 없습니다.

마지막으로 main() 함수에서는 I 타입의 변수 i를 선언하고, 이를 T 타입의 값으로 초기화합니다. 그리고 i.M()을 호출하여 T 타입의 M() 메서드를 실행합니다.

go
func main() {
	var i I = T{"hello"}
	i.M()
}
 
go
func main() {
	var i I = T{"hello"}
	i.M()
}
 

이 코드를 실행하면 T 타입의 S 필드 값인 "hello"가 출력됩니다.

이처럼 Go 언어에서는 인터페이스를 암시적으로 구현할 수 있습니다. 이는 인터페이스와 구현체 간의 결합도를 낮추고, 코드의 유연성을 높이는 데 도움을 줍니다. 우리는 인터페이스를 정의하고, 해당 인터페이스의 메서드를 구현하기만 하면 됩니다. 이를 통해 다양한 타입들이 동일한 인터페이스를 구현할 수 있게 되며, 이는 코드의 재사용성과 확장성을 증대시킵니다.

YouTube 영상

채널 보기
Product와 Coproduct가 Bifunctor인 이유 | 프로그래머를 위한 카테고리 이론
NestJS 전역 에러 처리 | NestJS 가이드
NestJS 커스텀 예외 만들기 - 에러 처리 깔끔하게 하는 법 | NestJS 가이드
NestJS 미들웨어 기초 - 클래스 기반 미들웨어와 DI | NestJS 가이드
List 펑터 - 왜 map은 for 루프보다 강력한가? | 프로그래머를 위한 카테고리 이론
미들웨어 적용과 라우팅 | NestJS 가이드
Const 펑터 - 아무것도 안 하는 펑터가 필요한 이유 | 프로그래머를 위한 카테고리 이론
Maybe 펑터와 타입 들어올리기 | 프로그래머를 위한 카테고리 이론