Go 1.21 버전 변경점 정리

기본적으로 Go는 하위호환을 제공하려 노력하므로, 이전 버전의 프로젝트는 Go 1.21 버전에서도 정상적으로 컴파일되고 실행된다.

그럼 어떤 것들이 달라졌는지 직접 알아보자.

릴리즈노트 링크

새로운 내장함수

min과 max 함수 추가

많은 언어에서 내장함수로 제공하는 min, max 함수가 추가되었다.

문서링크

min(x, y)    == min(y, x)
min(x, y, z) == min(min(x, y), z) == min(x, min(y, z))

map과 slice를 위한 clear 함수 추가

map의 경우 map 내부의 key, value를 모두 제거하며, slice의 경우 zero value로 초기화한다.

s := []int{0, 1, 2, 3, 4, 5}
clear(s) // []int len: 6, cap: 6, [0,0,0,0,0,0]

m := map[string]string{"key": "value"}
clear(m) // map[string]string []

Core Library

새로운 log/slog 패키지

https://pkg.go.dev/log/slog

구조화된 logging을 도와주는 패키지다. 로그레벨을 지정할 수 있고, key, value 페어 형태로 로그를 남길 수 있다.

TextHandler, JSONHandler가 각각 제공되는데, TextHandler를 이용하면 key1=value1 key2=value2 형식으로, JSONHandler를 이용하면 {"key1": "value1", "key2": "value2"} 형식으로 로깅을 남길 수 있다.

// TextHandler
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
****logger.Info("hello", "count", 3)
// time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3

// JSONHandler
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("hello", "count", 3)
// {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3}

로그 레벨

로그 레벨도 지정할 수 있는데, debug, info, warn, error가 제공된다.

const (
	LevelDebug Level = -4
	LevelInfo  Level = 0
	LevelWarn  Level = 4
	LevelError Level = 8
)

전역으로도 지정할 수도 있고,

필요할 때 아래처럼 사용하는 것도 가능하다.

msg := map[string]interface{}{
		"name": "Alice",
		"age":  29,
	}

logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

logger.Error("request_error", "errors", msg)
// {"time":"2023-08-14T13:18:54.118471294+09:00","level":"ERROR","msg":"request_error","errors":{"age":29,"name":"Alice"}}

logger.Info("incoming request", "request_body", msg)
// {"time":"2023-08-14T13:18:54.118564116+09:00","level":"INFO","msg":"request_body","request":{"age":29,"name":"Alice"}}

새로운 slices 패키지

https://pkg.go.dev/slices

슬라이스를 다룰 수 있는 여러 함수들과 타입들을 제공한다.

Binary Search

주어진 target을 정렬된 slice에서 찾으며 target의 위치와 존재여부를 반환한다.

names := []string{"Alice", "Bob", "Vera"}
n, found := slices.BinarySearch(names, "Vera")
fmt.Println("Vera:", n, found) // Vera: 2 true

Clone

주어진 슬라이스를 복제해 새 슬라이스를 반환한다.

assignment를 이용해 복사되는 얕은 복사(shallow clone)이 진행된다.

names := []string{"Alice", "Bob", "Vera"}
namesCopied:= slices.Clone(names)
fmt.Println(namesCopied) // [Alice Bob Vera]

Contains

주어진 슬라이스에 주어진 target이 존재하는지 여부를 boolean으로 반환한다.

names := []string{"Alice", "Bob", "Vera"}
slices.Contains(names, "Vera") // true

Max, Min

Max는 최댓값을, Min은 최솟값을 반환하며, 슬라이스가 비어 있다면 panic이 발생한다.

numbers := []int{0, 42, -10, 8}
fmt.Println(slices.Max(numbers)) // 42

Replace

slices.Replace(<slice>, <i>, <j>, …values)

슬라이스 s에 대해 s[i:j] 값을 주어진 value들로 치환하고 수정된 슬라이스를 반환한다.

names := []string{"Alice", "Bob", "Vera", "Zac"}
names = slices.Replace(names, 1, 3, "Bill", "Billie", "Cat")
fmt.Println(names) // [Alice Bill Billie Cat Zac]

Reverse

slice의 값의 순서를 반전시킨다.

names := []string{"alice", "Bob", "VERA"}
slices.Reverse(names)
fmt.Println(names) // [VERA Bob alice]

Sort

주어진 슬라이스를 오름차순으로 정렬한다.

smallInts := []int8{0, 42, -10, 8}
slices.Sort(smallInts)
fmt.Println(smallInts) // [-10 0 8 42]

새로운 maps 패키지

https://pkg.go.dev/maps

map을 다루는 다양한 함수와 타입을 제공한다.

Clone

얕은 복사가 진행되며 map을 복사해 새 map을 반환한다.

Copy

주어진 map에서 key, value를 모두 복사해 주어진 목적지 map으로 붙여넣는다.

즉, src → dist로 복사하게 된다. 만약 dist에 이미 존재하는 key 값을 붙여넣으려고 할 경우, 덮어쓰기가 진행된다.

src := map[string]interface{}{
		"name":    "Alice",
		"age":     29,
		"address": "Seoul",
}

dist := map[string]interface{}{
		"name":  "Leon",
		"phone": "111-1111",
}

maps.Copy(dist, src)
fmt.Println(dist) // map[address:Seoul age:29 name:Alice phone:111-1111]

Equal

두개의 map이 동일한 key, value를 가지고 있는지 검증한다.

src := map[string]interface{}{
		"name": "Alice",
		"age":  29,
}

dist := map[string]interface{}{
		"name": "Alice",
		"age":  29,
}

res := maps.Equal(dist, src)

fmt.Println(res) // true

새로운 cmp 패키지

https://pkg.go.dev/cmp

cmp 패키지는 value 간 비교나 정렬을 위해 사용된다.

문서링크

func Compare[T Ordered](x, y T) int

// x > y인 경우, 1
// x == y인 경우, 0
// x < y인 경우 -1

func Less[T Ordered](x, y T) bool

컴파일러 & 런타임

PGO(Profile-guide optimization)을 지원한다. PGO는 추가적인 최적화를 제공하는 데, 사용시 2~7% 정도 성능이 개선된다고 한다. 빌드속도 역시 6% 정도 개선된다.

가비지 컬렉션 튜닝을 통해 tail latency도 최대 40%까지 줄어들게 된다.