제네릭(Generic)이란, 특정 타입에 의존하지 않고 다양한 타입을 지원하는 프로그래밍 기법입니다. 즉, 같은 코드로 여러 타입을 처리할 수 있도록 해주는 기능입니다. 쉽게 말해서 **“하나의 코드로 여러 타입을 다룰 수 있게 해주는 도구”**입니다.
일반적으로 함수나 구조체는 특정 타입에 종속됩니다. 예를 들어, 두 개의 숫자를 더하는 함수를 만든다고 하면 아래와 같습니다.
func AddInt(a, b int) int {
return a + b
}
func AddFloat(a, b float64) float64 {
return a + b
}
위처럼 int와 float64를 각각 처리하는 별도의 함수를 만들어야 합니다. 하지만 제네릭을 사용하면 아래와 같이 하나의 코드로 여러 타입을 지원할 수 있습니다.
package main
import "fmt"
// 제네릭을 사용한 함수
// T는 타입 매개변수로, int 또는 float64 타입을 가질 수 있습니다.
func Add[T int | float64](a, b T) T {
return a + b
}
func main() {
fmt.Println(Add(3, 5)) // int 타입
fmt.Println(Add(3.2, 5.8)) // float64 타입
}
func Add[T any](a, b T) T
func Add[T int | float64](a, b T) T
: 숫자 타입만 허용// generic을 사용하지 않은 경우
func AddInt(a, b int) int {
return a + b
}
func AddFloat(a, b float64) float64 {
return a + b
}
// generic을 사용한 경우
func Add[T int | float64](a, b T) T {
return a + b
}
func main() {
fmt.Println(Add(3, 5)) // int 타입
fmt.Println(Add(3.2, 5.8)) // float64 타입
}
package main
import "fmt"
// 제네릭을 지원하는 구조체
type Box[T any] struct {
value T
}
func main() {
intBox := Box[int]{value: 10}
stringBox := Box[string]{value: "Hello"}
fmt.Println(intBox.value) // 10
fmt.Println(stringBox.value) // Hello
}
package main
import "fmt"
// 제네릭 인터페이스
type Printer[T any] interface {
Print(T)
}
// 구조체가 인터페이스를 구현
type ConsolePrinter[T any] struct{}
func (cp ConsolePrinter[T]) Print(value T) {
fmt.Println(value)
}
func main() {
intPrinter := ConsolePrinter[int]{}
intPrinter.Print(42)
stringPrinter := ConsolePrinter[string]{}
stringPrinter.Print("Hello, Go!")
}