제네릭 소개
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 67번째.
Go 1.18 이전에는 여러 타입에 사용할 수 있는 재사용 가능한 코드를 작성하려면 함수를 복제하거나 타입 단언과 함께 빈 인터페이스 any를 사용해야 했습니다. 제네릭을 사용하면 완전한 타입 안전성을 유지하면서 여러 타입에 작동하는 함수와 타입을 작성할 수 있으므로 이 문제를 해결할 수 있습니다.
슬라이스에서 최솟값을 찾는다고 생각해 보세요. 제네릭이 없다면 각 타입마다 별도의 함수가 필요합니다.
func MinInt(values []int) int {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}
func MinFloat64(values []float64) float64 {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}제네릭을 사용하면 대괄호 안에 타입 매개변수를 넣어 로직을 한 번만 작성할 수 있습니다.
func Min[T int | float64](values []T) T {
min := values[0]
for _, v := range values {
if v < min {
min = v
}
}
return min
}[T int | float64]는 int 또는 float64가 될 수 있는 타입 매개변수 T를 선언합니다. 이제 같은 함수로 Min([]int{3, 1, 2}) 또는 Min([]float64{3.5, 1.2})를 호출할 수 있습니다. 컴파일러가 컴파일 시점에 타입을 검사하므로 런타임 오버헤드 없이 안전성을 확보할 수 있습니다.
앞으로의 수업에서는 타입 매개변수, 제약 조건, 제네릭 구조체를 자세히 살펴보겠습니다.
챌린지
쉬움제네릭을 사용해 정수 점수와 부동 소수점 점수 모두를 처리하는 점수 분석기를 만들어 봅시다! 슬라이스에서 최댓값을 찾을 수 있는 제네릭 함수 하나를 만들어 숫자 유형마다 코드를 중복해서 작성할 필요가 없도록 합니다.
코드를 두 파일에 나누어 작성합니다.
analyzer.go: 제네릭 분석 함수를 정의합니다.슬라이스에서 최댓값을 찾아 반환하는 제네릭 함수
Max[T int | float64](values []T) T를 만듭니다. 이 함수는 타입 매개변수T를 통해int와float64유형 모두에서 작동해야 합니다.또한 슬라이스의 모든 값의 합을 계산해 반환하는 제네릭 함수
Sum[T int | float64](values []T) T도 만듭니다.main.go: 입력을 읽고 서로 다른 유형으로 제네릭 함수를 실행해 봅니다.유형 표시자(
int또는float)를 읽은 다음, 개수를 읽고 그 개수만큼 값을 읽습니다. 유형에 따라 값을 파싱하고, 적절한 유형으로Max와Sum을 모두 호출한 후 결과를 출력합니다.정수 입력의 경우 다음을 출력합니다.
Max (int): [value] Sum (int): [value]부동 소수점 입력의 경우 소수점 이하 한 자리까지 출력합니다.
Max (float): [value] Sum (float): [value]
다음 입력이 제공됩니다.
- 1번째 줄: 유형 표시자(
int또는float) - 2번째 줄: 값의 개수(정수)
- 그다음 줄들: 줄마다 값 하나
예를 들어, 다음이 주어지면:
int
4
15
8
23
11다음과 같이 출력해야 합니다.
Max (int): 23
Sum (int): 57그리고 다음이 주어지면:
float
3
4.5
9.2
6.8다음과 같이 출력해야 합니다.
Max (float): 9.2
Sum (float): 20.5같은 제네릭 함수가 정수 데이터와 부동 소수점 데이터 모두를 처리하는 방식을 살펴보세요. 타입 매개변수 [T int | float64]를 사용하면 로직은 한 번만 작성하면서 컴파일러가 각 사용 사례에 맞는 타입 안전 코드를 생성할 수 있습니다.
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 타입 표시자를 읽기
typeStr, _ := reader.ReadString('\n')
typeStr = strings.TrimSpace(typeStr)
// 개수를 읽기
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
if typeStr == "int" {
// 정수 값을 읽기
values := make([]int, count)
for i := 0; i < count; i++ {
line, _ := reader.ReadString('\n')
values[i], _ = strconv.Atoi(strings.TrimSpace(line))
}
// TODO: 정수 슬라이스로 Max와 Sum 호출하기
// TODO: 결과를 "Max (int): [value]"와 "Sum (int): [value]" 형식으로 출력하기
} else if typeStr == "float" {
// 실수 값을 읽기
values := make([]float64, count)
for i := 0; i < count; i++ {
line, _ := reader.ReadString('\n')
values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
}
// TODO: float64 슬라이스로 Max와 Sum 호출하기
// TODO: 결과를 소수점 첫째 자리까지 "Max (float): [value]"와 "Sum (float): [value]" 형식으로 출력하기
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러