go 의 특이한 특징으로 interface{} (empty interface) 를 많이 사용합니다.

아무런 메소드를 구현할 필요가 없는, 즉 모든 타입을 담을 수 있습니다.

C# JAVAObject, 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