인터페이스는 (1) 구체화된 타입으로 변환할 수도 있고, (2) 다른 인터페이스로 변환할 수도 있습니다.
interface.(type) 꼴로 두 경우 다 방법은 똑같습니다.
인터페이스 변수에서 다른 구체화된 타입으로 변환하기
인터페이스 변수에서는 인터페이스에 해당하는 구조체의 필드에 직접 접근할 수 없습니다.
따라서 인터페이스 변수를 받는 함수는 변수를 구조체로 타입 변환해줄 필요가 있습니다.
아래 코드를 보면 직관적으로 이해할 수 있습니다.
package main
import "fmt"
// String 메서드를 가지면 모두 Stringer 인터페이스 타입
type Stringer interface{
String() string
}
type Student struct {
Age int
}
// Student에 String 메서드 추가. 이로써 Stringer 인터페이스 타입이 됨.
func (s *Student) String() string {
return fmt.Sprintf("Student Age:%d", s.Age)
}
func PrintAge(stringer Stringer) {
fmt.Println(stringer.String()) // 인터페이스 변수에서 접근가능한 건 정의한 메서드 뿐임
// struct의 변수에 접근하기 위해 인터페이스 변수를 구체적인 타입으로 변환. 여기선 *Student struct로 변환
s := stringer.(*Student)
fmt.Printf("Age : %d\n", s.Age)
}
func main() {
s := &Student{Age: 15}
PrintAge(s)
}
위 코드도 작동하지만 좀 더 꼼꼼하게 변환을 하려면, 타입 변환이 성공했는지의 여부를 두번째 반환값으로 받을 수 있습니다.
변환이 성공적이라면 true를, 실패라면 false를 반환합니다. 잘 체크해서 런타임 오류를 발생시키지 않도록 합시다.
func PrintAge(stringer Stringer) {
// 타입 변환 결과가 성공적이라면 ok가 true, 실패면 false 반환
s, ok := stringer.(*Student)
if !ok {
fmt.Println("error")
}
fmt.Printf("Age : %d\n", s.Age)
}
위 코드도 길다! 하면 아래처럼 한 줄로 작성할 수도 있습니다. 변환 결과가 true면 if문 이하를 실행하고 아니면 else로 빠지는 식으로요.
func PrintAge(stringer Stringer) {
if s, ok := stringer.(*Student); ok {
fmt.Printf("Age : %d\n", s.Age)
} else {
fmt.Println("error")
}
}
'Programming Language > 🐿️ Go (Golang)' 카테고리의 다른 글
interface (1) : 구조체를 추상화해보자 (0) | 2021.05.15 |
---|---|
Go func (2) : defer, 함수 리터럴(익명함수), 값으로서의 함수, callback, closure (0) | 2021.05.15 |
Go func (1) : pass by reference, 가변 인자 함수, Multiple return, naked return (0) | 2021.05.15 |
struct (2) : 구조체의 메서드 + pointer receiver + error handling (0) | 2021.05.15 |
struct (1) : struct(구조체)를 생성, 메모리 패딩, struct factory (2) | 2021.05.15 |