[Go] min/max
Updated:
개요
Go 1.21부터 추가된 min과 max 내장 함수는 비교 가능한 값들 중 최소값과 최대값을 반환합니다.
주요 특징:
- 내장 함수: import 없이 사용 가능
- 가변 인자: 2개 이상의 값 비교
- 타입 안전: 컴파일 타임 타입 체크
- Ordered 타입: 정수, 실수, 문자열 지원
- 간결성: if 문이나 반복문 불필요
- 성능: 최적화된 구현
- NaN 처리: 특수 케이스 지원
기본 사용법
1. 정수 타입
package main
import "fmt"
func main() {
// int
fmt.Println(min(1, 2)) // 1
fmt.Println(max(1, 2)) // 2
// 여러 값 비교
fmt.Println(min(5, 3, 8, 1, 9)) // 1
fmt.Println(max(5, 3, 8, 1, 9)) // 9
// int64
var a, b int64 = 100, 200
fmt.Println(min(a, b)) // 100
fmt.Println(max(a, b)) // 200
// uint
var x, y uint = 10, 20
fmt.Println(min(x, y)) // 10
fmt.Println(max(x, y)) // 20
// 음수
fmt.Println(min(-5, -2, -10)) // -10
fmt.Println(max(-5, -2, -10)) // -2
}
2. 실수 타입
func main() {
// float64
fmt.Println(min(3.14, 2.71)) // 2.71
fmt.Println(max(3.14, 2.71)) // 3.14
// 여러 실수
fmt.Println(min(1.1, 2.2, 3.3, 0.5)) // 0.5
fmt.Println(max(1.1, 2.2, 3.3, 0.5)) // 3.3
// float32
var f1, f2 float32 = 1.5, 2.5
fmt.Println(min(f1, f2)) // 1.5
fmt.Println(max(f1, f2)) // 2.5
// 0과 음수
fmt.Println(min(0.0, -1.0, 1.0)) // -1
fmt.Println(max(0.0, -1.0, 1.0)) // 1
}
3. 문자열 타입
func main() {
// 문자열 비교 (사전순)
fmt.Println(min("apple", "banana")) // apple
fmt.Println(max("apple", "banana")) // banana
// 여러 문자열
fmt.Println(min("go", "rust", "python", "c")) // c
fmt.Println(max("go", "rust", "python", "c")) // rust
// 대소문자 구분
fmt.Println(min("Apple", "apple")) // Apple (대문자가 작음)
fmt.Println(max("Apple", "apple")) // apple
// 길이와 무관
fmt.Println(min("a", "aaa")) // a
fmt.Println(min("b", "aaa")) // aaa (b > a)
}
4. 단일 값
func main() {
// 단일 값도 허용
fmt.Println(min(42)) // 42
fmt.Println(max(42)) // 42
// 문자열도 동일
fmt.Println(min("hello")) // hello
fmt.Println(max("hello")) // hello
}
타입 제약
1. cmp.Ordered
import "cmp"
// min과 max가 지원하는 타입들
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
// 사용자 정의 타입도 가능
type MyInt int
func main() {
var a, b MyInt = 10, 20
fmt.Println(min(a, b)) // 10
fmt.Println(max(a, b)) // 20
}
2. 컴파일 에러
func main() {
// bool은 Ordered가 아님
// min(true, false) // 컴파일 에러
// 구조체는 Ordered가 아님
type Point struct{ X, Y int }
// min(Point{1, 2}, Point{3, 4}) // 컴파일 에러
// 슬라이스는 비교 불가
// min([]int{1}, []int{2}) // 컴파일 에러
// 다른 타입 혼용 불가
// min(1, 1.5) // 컴파일 에러 (int와 float64)
}
3. 타입 일관성
func main() {
// 모든 인자는 같은 타입이어야 함
var a int = 1
var b int = 2
fmt.Println(min(a, b)) // OK
// 타입 변환 필요
var x int = 1
var y int64 = 2
// min(x, y) // 에러
fmt.Println(min(int64(x), y)) // OK
// 리터럴은 타입 추론
fmt.Println(min(1, 2, 3)) // OK (모두 int)
fmt.Println(min(1.0, 2.0, 3.0)) // OK (모두 float64)
}
이전 방법과 비교
1. if 문 사용
// Go 1.20 이전
func minOld(a, b int) int {
if a < b {
return a
}
return b
}
func maxOld(a, b int) int {
if a > b {
return a
}
return b
}
// Go 1.21+
func main() {
// 간결하고 명확
result := min(10, 20) // 10
result = max(10, 20) // 20
}
2. 삼항 연산자 대체
// Go에는 삼항 연산자가 없음
// 다른 언어: result = (a < b) ? a : b
// Go 1.20 이전
func getMin(a, b int) int {
if a < b {
return a
}
return b
}
// Go 1.21+
func getMin(a, b int) int {
return min(a, b) // 훨씬 간결
}
3. 여러 값 비교
// Go 1.20 이전 - 반복문
func minSlice(values []int) int {
if len(values) == 0 {
panic("empty slice")
}
minimum := values[0]
for _, v := range values[1:] {
if v < minimum {
minimum = v
}
}
return minimum
}
// Go 1.21+ - 훨씬 간단
func main() {
values := []int{5, 3, 8, 1, 9}
// 슬라이스를 직접 전달할 수는 없지만
// min(values...) // 에러: 슬라이스는 전개 불가
// 명시적 전달
result := min(5, 3, 8, 1, 9) // 1
// 또는 슬라이스 순회 함수 사용
result = minSlice(values)
}
4. math 패키지
import "math"
func main() {
// math 패키지는 float64만 지원
x := math.Min(1.5, 2.5) // 1.5
y := math.Max(1.5, 2.5) // 2.5
// int는 변환 필요
a, b := 10, 20
minInt := int(math.Min(float64(a), float64(b)))
// 내장 함수는 타입 변환 불필요
minInt = min(a, b) // 훨씬 간단
// math는 2개 값만 비교
result := math.Min(math.Min(1.0, 2.0), 3.0)
// 내장 함수는 가변 인자
result = min(1.0, 2.0, 3.0) // 간결
}
특수 케이스
1. NaN 처리
import "math"
func main() {
nan := math.NaN()
// NaN과 비교 시 NaN 반환
fmt.Println(min(nan, 1.0)) // NaN
fmt.Println(max(nan, 1.0)) // NaN
// 여러 값 중 하나라도 NaN이면 NaN
fmt.Println(min(1.0, nan, 3.0)) // NaN
fmt.Println(max(1.0, 2.0, nan)) // NaN
// NaN 확인
result := min(nan, 1.0)
if math.IsNaN(result) {
fmt.Println("Result is NaN")
}
}
2. 무한대 처리
import "math"
func main() {
inf := math.Inf(1) // +Inf
ninf := math.Inf(-1) // -Inf
// 무한대와 비교
fmt.Println(min(inf, 100.0)) // 100
fmt.Println(max(inf, 100.0)) // +Inf
fmt.Println(min(ninf, 100.0)) // -Inf
fmt.Println(max(ninf, 100.0)) // 100
// 무한대끼리 비교
fmt.Println(min(inf, ninf)) // -Inf
fmt.Println(max(inf, ninf)) // +Inf
}
3. 제로 값
func main() {
// 양수 제로와 음수 제로
posZero := 0.0
negZero := math.Copysign(0, -1)
// Go의 min/max는 +0과 -0를 구분하지 않음
fmt.Println(min(posZero, negZero)) // 0 또는 -0
fmt.Println(max(posZero, negZero)) // 0 또는 -0
// 정수는 제로만 존재
fmt.Println(min(0, 0)) // 0
}
4. 같은 값들
func main() {
// 모든 값이 같을 때
fmt.Println(min(5, 5, 5, 5)) // 5
fmt.Println(max(5, 5, 5, 5)) // 5
// 문자열도 동일
fmt.Println(min("a", "a", "a")) // a
fmt.Println(max("a", "a", "a")) // a
}
실전 예제
1. 범위 제한 (Clamp)
func clamp(value, minVal, maxVal int) int {
return max(minVal, min(value, maxVal))
}
func main() {
// 값을 범위 내로 제한
fmt.Println(clamp(5, 0, 10)) // 5 (범위 내)
fmt.Println(clamp(-5, 0, 10)) // 0 (최소값으로)
fmt.Println(clamp(15, 0, 10)) // 10 (최대값으로)
// 실수에도 적용
clampFloat := func(value, minVal, maxVal float64) float64 {
return max(minVal, min(value, maxVal))
}
fmt.Println(clampFloat(3.14, 0.0, 5.0)) // 3.14
fmt.Println(clampFloat(-1.0, 0.0, 5.0)) // 0.0
fmt.Println(clampFloat(10.0, 0.0, 5.0)) // 5.0
}
2. 슬라이스 최소/최대값
func minSlice(values []int) (int, bool) {
if len(values) == 0 {
return 0, false
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result, true
}
func maxSlice(values []int) (int, bool) {
if len(values) == 0 {
return 0, false
}
result := values[0]
for _, v := range values[1:] {
result = max(result, v)
}
return result, true
}
func main() {
numbers := []int{5, 3, 8, 1, 9, 2}
if minVal, ok := minSlice(numbers); ok {
fmt.Println("Min:", minVal) // Min: 1
}
if maxVal, ok := maxSlice(numbers); ok {
fmt.Println("Max:", maxVal) // Max: 9
}
}
3. 제네릭 Min/Max
import "cmp"
func Min[T cmp.Ordered](values []T) (T, bool) {
if len(values) == 0 {
var zero T
return zero, false
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result, true
}
func Max[T cmp.Ordered](values []T) (T, bool) {
if len(values) == 0 {
var zero T
return zero, false
}
result := values[0]
for _, v := range values[1:] {
result = max(result, v)
}
return result, true
}
func main() {
// int 슬라이스
ints := []int{5, 3, 8, 1, 9}
minInt, _ := Min(ints)
maxInt, _ := Max(ints)
fmt.Printf("Int: min=%d, max=%d\n", minInt, maxInt)
// float64 슬라이스
floats := []float64{1.1, 2.2, 0.5, 3.3}
minFloat, _ := Min(floats)
maxFloat, _ := Max(floats)
fmt.Printf("Float: min=%.1f, max=%.1f\n", minFloat, maxFloat)
// string 슬라이스
strings := []string{"go", "rust", "python", "c"}
minStr, _ := Min(strings)
maxStr, _ := Max(strings)
fmt.Printf("String: min=%s, max=%s\n", minStr, maxStr)
}
출력:
Int: min=1, max=9
Float: min=0.5, max=3.3
String: min=c, max=rust
4. 좌표 범위
type Point struct {
X, Y int
}
func boundingBox(points []Point) (minX, minY, maxX, maxY int, ok bool) {
if len(points) == 0 {
return 0, 0, 0, 0, false
}
minX, maxX = points[0].X, points[0].X
minY, maxY = points[0].Y, points[0].Y
for _, p := range points[1:] {
minX = min(minX, p.X)
maxX = max(maxX, p.X)
minY = min(minY, p.Y)
maxY = max(maxY, p.Y)
}
return minX, minY, maxX, maxY, true
}
func main() {
points := []Point{
{X: 1, Y: 2},
{X: 5, Y: 8},
{X: 3, Y: 1},
{X: 7, Y: 4},
}
minX, minY, maxX, maxY, ok := boundingBox(points)
if ok {
fmt.Printf("Bounding box: (%d,%d) to (%d,%d)\n",
minX, minY, maxX, maxY)
}
// Bounding box: (1,1) to (7,8)
}
5. 윈도우 크기 조정
type Window struct {
Width int
Height int
}
const (
MinWidth = 400
MaxWidth = 1920
MinHeight = 300
MaxHeight = 1080
)
func (w *Window) Resize(width, height int) {
// 범위 제한
w.Width = max(MinWidth, min(width, MaxWidth))
w.Height = max(MinHeight, min(height, MaxHeight))
}
func main() {
window := &Window{Width: 800, Height: 600}
fmt.Printf("Initial: %dx%d\n", window.Width, window.Height)
// 정상 범위
window.Resize(1024, 768)
fmt.Printf("After resize: %dx%d\n", window.Width, window.Height)
// 최소값보다 작게
window.Resize(100, 100)
fmt.Printf("Too small: %dx%d\n", window.Width, window.Height)
// 최대값보다 크게
window.Resize(3000, 2000)
fmt.Printf("Too large: %dx%d\n", window.Width, window.Height)
}
출력:
Initial: 800x600
After resize: 1024x768
Too small: 400x300
Too large: 1920x1080
6. 점수 정규화
func normalizeScores(scores []float64) []float64 {
if len(scores) == 0 {
return scores
}
// 최소/최대값 찾기
minScore := scores[0]
maxScore := scores[0]
for _, score := range scores {
minScore = min(minScore, score)
maxScore = max(maxScore, score)
}
// 0-100 범위로 정규화
normalized := make([]float64, len(scores))
scoreRange := maxScore - minScore
if scoreRange == 0 {
// 모든 점수가 같으면 50으로
for i := range normalized {
normalized[i] = 50.0
}
return normalized
}
for i, score := range scores {
normalized[i] = (score - minScore) / scoreRange * 100
}
return normalized
}
func main() {
scores := []float64{45.0, 67.0, 89.0, 23.0, 78.0}
fmt.Println("Original:", scores)
normalized := normalizeScores(scores)
fmt.Println("Normalized:", normalized)
}
출력:
Original: [45 67 89 23 78]
Normalized: [33.33 66.67 100 0 83.33]
7. 날짜 범위
import "time"
type DateRange struct {
Start time.Time
End time.Time
}
func (dr DateRange) Contains(t time.Time) bool {
return !t.Before(dr.Start) && !t.After(dr.End)
}
func mergeDateRanges(ranges []DateRange) DateRange {
if len(ranges) == 0 {
return DateRange{}
}
result := ranges[0]
for _, r := range ranges[1:] {
// 가장 이른 시작일
if r.Start.Before(result.Start) {
result.Start = r.Start
}
// 가장 늦은 종료일
if r.End.After(result.End) {
result.End = r.End
}
}
return result
}
// Go 1.21+ string 비교로 간단히
func earliestDate(dates ...string) string {
if len(dates) == 0 {
return ""
}
result := dates[0]
for _, d := range dates[1:] {
result = min(result, d)
}
return result
}
func latestDate(dates ...string) string {
if len(dates) == 0 {
return ""
}
result := dates[0]
for _, d := range dates[1:] {
result = max(result, d)
}
return result
}
func main() {
// ISO 8601 형식 (사전순 = 시간순)
dates := []string{
"2024-03-15",
"2024-01-20",
"2024-12-01",
"2024-06-10",
}
fmt.Println("Earliest:", earliestDate(dates...))
fmt.Println("Latest:", latestDate(dates...))
}
8. 가격 비교
type Product struct {
Name string
Price float64
}
func findCheapest(products []Product) (Product, bool) {
if len(products) == 0 {
return Product{}, false
}
cheapest := products[0]
for _, p := range products[1:] {
if p.Price < cheapest.Price {
cheapest = p
}
}
return cheapest, true
}
func findMostExpensive(products []Product) (Product, bool) {
if len(products) == 0 {
return Product{}, false
}
expensive := products[0]
for _, p := range products[1:] {
if p.Price > expensive.Price {
expensive = p
}
}
return expensive, true
}
func priceRange(products []Product) (min, max float64, ok bool) {
if len(products) == 0 {
return 0, 0, false
}
min, max = products[0].Price, products[0].Price
for _, p := range products[1:] {
min = min(min, p.Price) // 내장 함수 사용
max = max(max, p.Price)
}
return min, max, true
}
func main() {
products := []Product{
{Name: "Laptop", Price: 1200.00},
{Name: "Mouse", Price: 25.00},
{Name: "Keyboard", Price: 75.00},
{Name: "Monitor", Price: 300.00},
}
if cheapest, ok := findCheapest(products); ok {
fmt.Printf("Cheapest: %s ($%.2f)\n", cheapest.Name, cheapest.Price)
}
if expensive, ok := findMostExpensive(products); ok {
fmt.Printf("Most expensive: %s ($%.2f)\n", expensive.Name, expensive.Price)
}
if minPrice, maxPrice, ok := priceRange(products); ok {
fmt.Printf("Price range: $%.2f - $%.2f\n", minPrice, maxPrice)
}
}
출력:
Cheapest: Mouse ($25.00)
Most expensive: Laptop ($1200.00)
Price range: $25.00 - $1200.00
성능 고려사항
1. 벤치마크
package main
import "testing"
func BenchmarkMinBuiltin(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = min(10, 20)
}
}
func BenchmarkMinIfElse(b *testing.B) {
for i := 0; i < b.N; i++ {
a, b := 10, 20
var result int
if a < b {
result = a
} else {
result = b
}
_ = result
}
}
func BenchmarkMinMultiple(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = min(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
}
}
func BenchmarkMinLoop(b *testing.B) {
values := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for i := 0; i < b.N; i++ {
result := values[0]
for _, v := range values[1:] {
if v < result {
result = v
}
}
_ = result
}
}
예상 결과:
BenchmarkMinBuiltin 1000000000 0.25 ns/op
BenchmarkMinIfElse 1000000000 0.25 ns/op
BenchmarkMinMultiple 500000000 2.50 ns/op
BenchmarkMinLoop 100000000 10.00 ns/op
2. 인라인 최적화
// 컴파일러가 min/max를 인라인 최적화
func clampInlined(value, minVal, maxVal int) int {
return max(minVal, min(value, maxVal))
// 최적화된 어셈블리 코드로 변환
}
// if 문도 비슷하게 최적화되지만
// min/max가 더 명확하고 읽기 쉬움
3. 가변 인자 오버헤드
// 2-3개 값: min/max 사용 권장
result := min(a, b) // 빠름
result = min(a, b, c) // 빠름
// 많은 값: 루프가 더 효율적일 수 있음
result = min(v1, v2, v3, ..., v100) // 가변 인자 오버헤드
// 슬라이스: 커스텀 함수 사용
result = minSlice(values) // 더 효율적
일반적인 실수
1. 슬라이스 직접 전달
// ❌ 나쁜 예
func main() {
values := []int{1, 2, 3, 4, 5}
// result := min(values...) // 컴파일 에러
}
// ✅ 좋은 예
func minSlice(values []int) int {
if len(values) == 0 {
panic("empty slice")
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result
}
2. 타입 불일치
// ❌ 나쁜 예
func main() {
var a int = 10
var b int64 = 20
// result := min(a, b) // 컴파일 에러
}
// ✅ 좋은 예
func main() {
var a int = 10
var b int64 = 20
result := min(int64(a), b) // 타입 변환
// 또는
result = int(min(a, int(b)))
}
3. NaN 무시
// ❌ 나쁜 예
func findMin(values []float64) float64 {
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result // NaN일 수 있음
}
// ✅ 좋은 예
func findMin(values []float64) float64 {
result := values[0]
for _, v := range values[1:] {
// NaN 체크
if math.IsNaN(v) {
continue
}
result = min(result, v)
}
return result
}
4. 빈 슬라이스 처리 누락
// ❌ 나쁜 예
func minValue(values []int) int {
result := values[0] // 패닉 가능!
for _, v := range values[1:] {
result = min(result, v)
}
return result
}
// ✅ 좋은 예
func minValue(values []int) (int, bool) {
if len(values) == 0 {
return 0, false
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result, true
}
5. 불필요한 반복 비교
// ❌ 비효율적
func getMiddle(a, b, c int) int {
if a < b {
if b < c {
return b
} else if a < c {
return c
} else {
return a
}
} else {
// ...복잡한 로직
}
}
// ✅ 간단하고 명확
func getMiddle(a, b, c int) int {
return max(min(a, b), min(max(a, b), c))
}
6. math.Min/Max와 혼동
// ❌ 타입 변환 실수
func main() {
a, b := 10, 20
// math.Min은 float64 반환
result := math.Min(float64(a), float64(b)) // 10.0
intResult := int(result) // 변환 필요
// 내장 함수는 타입 유지
intResult = min(a, b) // 10 (변환 불필요)
}
7. Clamp 구현 실수
// ❌ 나쁜 예 (잘못된 순서)
func clampWrong(value, minVal, maxVal int) int {
return min(maxVal, max(value, minVal))
// value가 maxVal보다 크면 잘못됨
}
// ✅ 좋은 예
func clamp(value, minVal, maxVal int) int {
return max(minVal, min(value, maxVal))
// 또는
if value < minVal {
return minVal
}
if value > maxVal {
return maxVal
}
return value
}
베스트 프랙티스
1. 명확한 변수 이름
// ✅ 좋은 예
func processTemperature(temp float64) float64 {
minTemp := -40.0
maxTemp := 50.0
return max(minTemp, min(temp, maxTemp))
}
// ❌ 나쁜 예
func processTemperature(t float64) float64 {
return max(-40.0, min(t, 50.0)) // 의미 불명확
}
2. 경계 값 상수화
const (
MinAge = 0
MaxAge = 120
MinSalary = 0.0
MaxSalary = 1000000.0
)
func validateAge(age int) int {
return max(MinAge, min(age, MaxAge))
}
func validateSalary(salary float64) float64 {
return max(MinSalary, min(salary, MaxSalary))
}
3. 제네릭 유틸리티 함수
import "cmp"
func Clamp[T cmp.Ordered](value, minVal, maxVal T) T {
return max(minVal, min(value, maxVal))
}
func InRange[T cmp.Ordered](value, minVal, maxVal T) bool {
return value >= minVal && value <= maxVal
}
func MinSlice[T cmp.Ordered](values []T) (T, bool) {
if len(values) == 0 {
var zero T
return zero, false
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result, true
}
func MaxSlice[T cmp.Ordered](values []T) (T, bool) {
if len(values) == 0 {
var zero T
return zero, false
}
result := values[0]
for _, v := range values[1:] {
result = max(result, v)
}
return result, true
}
4. 오류 처리
func SafeMin(values []int) (int, error) {
if len(values) == 0 {
return 0, fmt.Errorf("cannot find min of empty slice")
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result, nil
}
func SafeMax(values []int) (int, error) {
if len(values) == 0 {
return 0, fmt.Errorf("cannot find max of empty slice")
}
result := values[0]
for _, v := range values[1:] {
result = max(result, v)
}
return result, nil
}
5. 문서화
// Clamp restricts a value to be within a specified range.
// If value < minVal, returns minVal.
// If value > maxVal, returns maxVal.
// Otherwise, returns value unchanged.
//
// Example:
//
// Clamp(5, 0, 10) // returns 5
// Clamp(-5, 0, 10) // returns 0
// Clamp(15, 0, 10) // returns 10
func Clamp[T cmp.Ordered](value, minVal, maxVal T) T {
return max(minVal, min(value, maxVal))
}
6. 테스트
func TestClamp(t *testing.T) {
tests := []struct {
name string
value, min, max int
want int
}{
{"within range", 5, 0, 10, 5},
{"below min", -5, 0, 10, 0},
{"above max", 15, 0, 10, 10},
{"at min", 0, 0, 10, 0},
{"at max", 10, 0, 10, 10},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Clamp(tt.value, tt.min, tt.max)
if got != tt.want {
t.Errorf("Clamp(%d, %d, %d) = %d; want %d",
tt.value, tt.min, tt.max, got, tt.want)
}
})
}
}
7. 성능 최적화
// 작은 개수: 내장 함수 사용
func findMin2(a, b int) int {
return min(a, b) // 가장 빠름
}
func findMin3(a, b, c int) int {
return min(a, b, c) // 충분히 빠름
}
// 많은 개수: 루프 사용
func findMinMany(values ...int) int {
if len(values) == 0 {
return 0
}
result := values[0]
for _, v := range values[1:] {
result = min(result, v)
}
return result
}
8. Null 안전성
type OptionalInt struct {
value int
valid bool
}
func MinOptional(a, b OptionalInt) OptionalInt {
if !a.valid {
return b
}
if !b.valid {
return a
}
return OptionalInt{
value: min(a.value, b.value),
valid: true,
}
}
정리
- 기본: min(a, b, …), max(a, b, …) 2개 이상 인자
- 타입: cmp.Ordered (정수, 실수, 문자열)
- vs 이전: if 문, 삼항 연산자 대체, math 패키지보다 간편
- 특수: NaN 전파, 무한대 처리, 제로 값
- 실전: Clamp, 슬라이스, 범위, 정규화, 날짜, 가격
- 성능: 인라인 최적화, 2-3개 값에 최적
- 실수: 슬라이스 전달 불가, 타입 불일치, NaN, 빈 슬라이스
- 베스트: 상수화, 제네릭, 오류 처리, 문서화, 테스트