go
의 특이한 특징으로 interface{}
(empty interface) 를 많이 사용합니다.
아무런 메소드를 구현할 필요가 없는, 즉 모든 타입을 담을 수 있습니다.
C#
JAVA
의 Object
, C
개열 언어의 void*
와 비슷한 용도로 사용됩니다.
interface{}
는 다양하게 사용됩니다.
제네릭
go
는 제네릭이 없습니다.
대신 interface{}
를 활용하여 비슷하게 구현 할 수 있습니다.
캐스팅
interface{}
를 캐스팅하는 방법입니다.
// #1
package main
import "fmt"
func main() {
var v interface{}
v = 4
intV := v.(int)
fmt.Printf("%d\n", intV)
}
// 출력
4
하지만 다음처럼, 잘못된 값을 캐스팅 하면, 패닉을 일으킵니다.
package main
import "fmt"
func main() {
var v interface{}
v = `4`
intV := v.(int)
fmt.Printf("%d\n", intV)
}
panic: interface conversion: interface {} is string, not int
goroutine 1 [running]:
main.main()
/home/code/project/vomp/main.go:9 +0x45
exit status 2
다음처럼 수정하면 런타임 패닉을 방지할 수 있습니다.
package main
import "fmt"
func main() {
var v interface{}
v = `4`
intV, ok := v.(int)
if !ok {
println("v is not int")
} else {
fmt.Printf("%d\n", intV)
}
}
// 축약
package main
import "fmt"
func main() {
var v interface{}
v = `4`
if intV, ok := v.(int); !ok {
println("v is not int")
} else {
fmt.Printf("%d\n", intV)
}
}
// 출력
v is not int
타입 체크
reflect
패키지로 런타임에서 타입을 체크할 수 있습니다.
다음 함수는 입력 받은 값이나 타입을 reflect.Type
으로 리턴합니다.
reflect.TypeOf(v)
// 타입체크 예시1
package main
import (
"fmt"
"reflect"
)
func main() {
var v interface{}
v = "hello"
vType := reflect.TypeOf(v)
fmt.Printf("v Type: %s\n", vType.String())
}
package main
import (
"reflect"
)
func main() {
var v interface{}
v = "hello"
vType := reflect.TypeOf(v)
if vType.Kind() == reflect.Int {
println("v is int")
} else if vType.Kind() == reflect.String {
println("v is string")
}
}
구조체 활용
사용자 정의 타입인 구조체 또한 interface{}
를 사용할 수 있습니다.
// 값
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
tom := Person{Name: "Tom", Age: 20}
var v interface{}
v = tom
somePerson := v.(Person)
fmt.Printf("%#v\n", somePerson)
}
// 포인터
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
tom := &Person{Name: "Tom", Age: 20}
var v interface{}
v = tom
somePerson := v.(*Person)
fmt.Printf("%#v\n", somePerson)
}
// 출력
main.Person{Name:"Tom", Age:20}
다음처럼, 포인터 타입을 잘못 설정하면 패닉이 발생됩니다.
// 패닉 예시1
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
tom := &Person{Name: "Tom", Age: 20}
var v interface{}
v = tom
somePerson := v.(Person)
fmt.Printf("%#v\n", somePerson)
}
// 패닉 예시2
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func main() {
tom := Person{Name: "Tom", Age: 20}
var v interface{}
v = tom
somePerson := v.(*Person)
fmt.Printf("%#v\n", somePerson)
}
reflect
패키지로 구조체의 타입을 볼 수 있습니다.
package main
import (
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
tom := Person{Name: "Tom", Age: 20}
var v interface{}
v = tom
t := reflect.TypeOf(v)
println(t.String())
}
// 출력
main.Person