🔥 인터페이스 값

486자
6분

Go 언어에서 인터페이스 값은 값과 구체적인 타입의 튜플로 생각할 수 있어요.

(value, type)
 
go

인터페이스 값은 특정 기본 구체 타입의 값을 보유하고 있지요.

인터페이스가 (값, 타입)의 쌍을 담는 이유는 다음과 같아요.

  1. 다형성 지원
    • 인터페이스는 여러 타입의 값을 담을 수 있어야 해요.
    • 서로 다른 타입이 동일한 인터페이스를 구현할 수 있게 함으로써 다형성을 지원하죠.
    • 값과 타입을 함께 저장함으로써 인터페이스는 어떤 타입의 값이 저장되었는지 알 수 있게 됩니다.
  2. 메서드 호출의 동적 디스패치
    • 인터페이스 값에서 메서드를 호출할 때, 실제로는 저장된 타입의 메서드가 호출되어야 해요.
    • 이를 위해 인터페이스는 값뿐만 아니라 그 값의 타입 정보도 함께 저장하고 있어야 하죠.
    • 타입 정보를 바탕으로 적절한 타입의 메서드를 찾아 호출할 수 있게 됩니다.
  3. 타입 어써션 및 타입 스위치
    • 인터페이스 값을 특정 타입으로 변환하거나 타입을 검사하기 위해서는 타입 정보가 필요해요.
    • 인터페이스가 값과 함께 타입 정보를 저장하고 있기 때문에 타입 어써션과 타입 스위치가 가능하죠.
    • 이를 통해 인터페이스에 저장된 값을 원래의 타입으로 변환하거나 타입에 따른 분기 처리를 할 수 있습니다.

따라서 인터페이스가 (값, 타입)의 쌍을 담는 것은 Go 언어에서 다형성, 동적 디스패치, 타입 검사 등의 기능을 제공하기 위한 중요한 메커니즘이라고 할 수 있어요.

이를 통해 Go는 인터페이스를 중심으로 유연하고 확장 가능한 코드를 작성할 수 있는 기반을 마련하고 있죠.

인터페이스 값에서 메서드를 호출하면 기본 타입에서 동일한 이름의 메서드가 실행된답니다. 다음 예제 코드를 통해 인터페이스 값의 동작을 자세히 살펴보도록 해요.

package main
 
import (
	"fmt"
	"math"
)
 
// I는 M() 메서드를 가진 인터페이스
type I interface {
	M()
}
 
// T는 S 문자열 필드를 가진 구조체
type T struct {
	S string
}
 
// T 타입의 포인터 리시버로 M() 메서드 구현
func (t *T) M() {
	fmt.Println(t.S)
}
 
// F는 float64의 별칭 타입
type F float64
 
// F 타입의 값 리시버로 M() 메서드 구현
func (f F) M() {
	fmt.Println(f)
}
 
func main() {
	var i I // 인터페이스 변수 선언
 
	i = &T{"Hello"} // i에 T 타입 포인터 값 할당
	describe(i)     // i의 값과 타입 출력
	i.M()           // i의 M() 메서드 호출 (T.M() 호출)
 
	i = F(math.Pi) // i에 F 타입 값 할당
	describe(i)    // i의 값과 타입 출력
	i.M()          // i의 M() 메서드 호출 (F.M() 호출)
}
 
// i가 가진 실제 값과 타입 정보를 출력하는 함수
func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}
 
go

이 예제에서는 I 인터페이스를 정의하고, 이를 구현한 TF 타입을 선언했어요. main 함수에서는 인터페이스 변수 i를 선언하고 TF 타입의 값을 할당하면서 각각의 M() 메서드를 호출하고 있지요.

describe 함수는 인터페이스 값 i가 가진 실제 값과 타입 정보를 출력해 줍니다. 이를 통해 인터페이스가 서로 다른 타입의 값을 담을 수 있음을 알 수 있어요.

실행 결과를 보면 다음과 같아요:

(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
text

i&T{"Hello"}를 할당했을 때는 (&{Hello}, *main.T) 형태로 값과 타입이 출력되고, iF(math.Pi)를 할당했을 때는 (3.141592653589793, main.F) 형태로 출력되는 걸 확인할 수 있답니다.

이처럼 인터페이스는 값과 타입의 조합으로 다양한 타입의 값을 담을 수 있게 해주는 강력한 기능을 제공하고 있어요. 덕분에 Go 언어에서는 인터페이스를 활용한 유연하고 확장성 있는 코드를 작성할 수 있게 되지요.