golang

golang generic 사용으로 empty interface boxing, unboxing 코드 수정

kimbs0301 2024. 10. 6. 17:42

go의 interface {} (empty interface)는 모든 타입을 담을 수 있습니다.

JAVA, C#의 Object, C 계열 언어의 void* 와 비슷한 용도로 사용됩니다.

interface {}를 사용하다 보면 boxing, unboxing 발생합니다.

 

package main

import (
	"fmt"
	"reflect"
	"strconv"
)

func main() {
	var value1 int = 21
	fmt.Printf("main() value1 %x %T\n", &value1, &value1)
	Recursion(&value1) // boxing
	fmt.Println("")

	var value2 string = "21"
	fmt.Printf("main() value2 %x %T\n", &value2, &value2)
	Recursion(value2) // boxing
	fmt.Println("")
}

func Recursion(value interface{}) {
	fmt.Printf("Recursion() value: %x %T\n", &value, &value)

	vType := reflect.TypeOf(value)

	typeKind := vType.Kind()
	var n int = 0
	if typeKind == reflect.Int {
		valueInt, _ := value.(int) // unboxing
		fmt.Printf("Recursion() value (%d) is int\n", valueInt)

		fmt.Printf("Recursion() int value: %x %T\n", &valueInt, &valueInt)
		n = recursion(valueInt)
	} else if typeKind == reflect.Pointer {
		valueInt := *(value.(*int)) // unboxing
		fmt.Printf("Recursion() value (%d) is *int\n", valueInt)

		fmt.Printf("Recursion() int value: %x %T\n", &valueInt, &valueInt)
		n = recursion(valueInt)
	} else if typeKind == reflect.String {
		valueString := value.(string) // unboxing
		fmt.Printf("Recursion() value (%s) is string\n", valueString)

		if i, err := strconv.ParseInt(valueString, 10, 32); err == nil {
			n = recursion(int(i))
		} else {
			n = recursion(1)
		}
	} else {
		fmt.Printf("Recursion() value Type: %s\n", vType.String())
		n = recursion(1)
	}

	fmt.Printf("result %d\n", n)
}

func recursion(n int) int {
    if n == 1 || n == 2 {
        return 1
    } else {
        return recursion(n - 1) + recursion(n - 2)
    }
}

 

실행결과>

main() value1 c00000a210 *int
Recursion() value: c000020280 *interface {}
Recursion() value (21) is *int
Recursion() int value: c00000a218 *int
result 10946

main() value2 c000020290 *string
Recursion() value: c0000202b0 *interface {}
Recursion() value (21) is string
result 10946

 

 

아래 소스코드는 새로 추가된 generic으로 수정된 내용입니다.

 

package main

import (
	"fmt"
	"strconv"

	"golang.org/x/exp/constraints"
)

func main() {
	var value1 int = 21
	fmt.Printf("main() value1 %x %T\n", &value1, &value1)
	Recursion(value1)
	fmt.Println("")

	var value2 string = "21"
	fmt.Printf("main() value2 %x %T\n", &value2, &value2)
	RecursionByString(value2)
	fmt.Println("")
}

func Recursion[T constraints.Integer | constraints.Float](value T) {
	n := recursion(int(value))
	fmt.Printf("result %d\n", n)
}

func RecursionByString(value string) {
	var n int = 0
	if i, err := strconv.ParseInt(value, 10, 32); err == nil {
		n = recursion(int(i))
	} else {
		n = recursion(1)
	}
	fmt.Printf("result %d\n", n)
}

func recursion(n int) int {
    if n == 1 || n == 2 {
        return 1
    } else {
        return recursion(n - 1) + recursion(n - 2)
    }
}

 

실행결과>

main() value1 c00000a210 *int
result 10946

main() value2 c000020290 *string
result 10946

 

 

리턴값없는 함수 제네릭 사용할 수 있습니다.

func 함수명[T constaint](value1 T)
타입 파라미터: [T constaint]

 

제네릭은 여러 개의 파라미터와 함수 인자값도 사용할 수 있습니다.

func GenericPrint[T1 any, T2 any](value1 T1, value2 T2) {
	fmt.Println(value1, value2)
}

func Add[T any](value1, value2 T) T {
	return value1 + value2
}

 

'golang' 카테고리의 다른 글

golang windows service  (0) 2025.01.05
golang smtp email send  (0) 2025.01.05
golang gzip 압축 해제  (0) 2024.10.06
golang brotli 브로틀리 압축 해제  (0) 2024.10.06
golang gzip 압축  (0) 2024.10.01