-
Go 1.22의 새로운 기능: cmp.OrGo 2024. 7. 29. 21:12
안녕하세요?
Go 1.22가 출시된 지 꽤 많은 시간이 지났는데요.이제 제가 1.22 버전을 정리하는 시리즈의 마지막을 장식할 때가 왔습니다.
이전에 작성한
reflect.TypeFor
와slices.Concat
함수에 대한 글을 먼저 읽으시는게 좋을 듯 합니다.오늘 소개할 마지막 함수는 바로
cmp.Or
입니다.실제로 이 함수의 개발자는 Go Time 팟캐스트에서 이 함수를 "1.22의 숨겨진 보석"이라고 소개한 바 있습니다.
간단한 기능이지만 다양한 활용 가능성을 가지고 있으며, 그 탄생 배경에는 놀랍도록 긴 이야기가 숨겨져 있습니다.
cmp.Or
: 제네릭 기반 조건부 값 선택의 새로운 접근 방식cmp.Or
함수는 가변 개수의 인자를 받아, 첫 번째 non-zero 값을 반환하는 제네릭 함수입니다.모든 인자가 zero 값인 경우에는 zero 값을 반환합니다.
이 함수의 코드는 다음과 같습니다.
// Or returns the first of its arguments that is not equal to the zero value. // If no argument is non-zero, it returns the zero value. func Or[T comparable](vals ...T) T { var zero T for _, val := range vals { if val != zero { return val } } return zero }
Go에 대한 저의 기여가 대부분 그렇듯,
cmp.Or
함수 역시 매우 간결하고 직관적인 코드로 구현되었습니다.단순히 입력받은 인자들을 순회하면서 zero 값이 아닌 첫 번째 값을 반환하는 로직입니다.
cmp.Or
의 활용: 다양한 상황에서의 유연한 값 선택cmp.Or
함수는 주로 문자열 처리에서 빈 문자열("")을 대체할 기본값을 설정하는 데 사용됩니다.예를 들어, 환경 변수를 가져오는 코드에서 환경 변수가 설정되지 않은 경우 기본값을 사용하고 싶을 때
cmp.Or(os.Getenv("SOME_VARIABLE"), "default")
와 같이 사용할 수 있습니다.숫자나 포인터 타입에도 적용 가능하며, 저의 실제 코드베이스에서 발췌한 몇 가지 예시는 다음과 같습니다.
body := cmp.Or(page.Body, rawContent) name := cmp.Or(jwt.Username(), "Almanack") credits = append(credits, cmp.Or(credit.Name, credit.Byline)) metadata.InternalID = cmp.Or( xhtml.InnerText(rows.Value("slug")), xhtml.InnerText(rows.Value("internal id")), metadata.InternalID, ) scope.SetTag("username", cmp.Or(userinfo.Username(), "anonymous")) currentUl = cmp.Or( xhtml.Closest(currentUl.Parent, xhtml.WithAtom(atom.Ul)), currentUl, )
대부분의 경우 문자열에 대한 fallback 값을 제공하는 데 사용되지만, 마지막 예시에서는 non-nil
*html.Node
를 찾는 데 사용되는 것을 볼 수 있습니다.또한
cmp.Compare
함수와 함께 사용하여 다중 조건 비교를 구현할 수도 있습니다.// ... (Order struct 및 orders slice 정의) // Sort by customer first, product second, and last by higher price slices.SortFunc(orders, func(a, b Order) int { return cmp.Or( cmp.Compare(a.Customer, b.Customer), cmp.Compare(a.Product, b.Product), cmp.Compare(b.Price, a.Price), ) })
하지만
cmp.Or
함수는 short-circuit evaluation을 지원하지 않기 때문에, 첫 번째 조건이 참이더라도 나머지 조건들을 모두 평가하게 됩니다. 이는 성능 측면에서 고려해야 할 사항입니다.cmp.Or
의 탄생 배경: 오랜 기다림 끝에 얻은 결실cmp.Or
함수가 탄생하기까지는 오랜 시간이 걸렸습니다.2016년 Stephen Kampmann이
strings.First
함수를 제안했지만, 당시에는 체계적인 제안 시스템이 없었기 때문에 제대로 논의되지 못했습니다.2020년에는 제가 short-circuiting을 지원하는
??
연산자를 제안했지만, Go 언어에 제네릭이 도입되면 제네릭 함수로 구현할 수 있다는 의견이 제시되었습니다.제네릭이 Go 1.18 베타 버전에 추가된 후, 저는
reflect.Value.IsZero()
를 사용하여 zero 값 여부를 판단하는truthy
패키지를 작성했지만, 리플렉션 사용으로 인한 성능 저하 문제가 발생했습니다.결국 2022년에
comparable
타입에 대한 제네릭 함수인cmp.Or
를 제안하게 되었고, 이 제안이 받아들여져 Go 1.22에 포함되었습니다.cmp.Or
의 미래: 더욱 강력하고 유연한 Go 언어를 향하여cmp.Or
함수는 Go 언어의 표현력과 유연성을 향상시키는 데 기여할 것입니다.특히 제네릭과의 시너지를 통해 더욱 강력하고 안전한 코드 작성을 가능하게 할 것으로 기대됩니다.
앞으로 Go 언어가 어떻게 발전해 나갈지 기대하며,
cmp.Or
함수가 Go 생태계에 긍정적인 영향을 미치기를 바랍니다.참고:
- Go 1.22 Release Notes: https://tip.golang.org/doc/go1.22
- Proposal: Add cmp.Or: https://github.com/golang/go/issues/56211
- Discussion: Universal zero value: https://github.com/golang/go/discussions/57524
더 깊이 있는 학습을 위한 자료:
- Go Time Podcast Episode on cmp.Or: [관련 에피소드 링크]
- Understanding Go Generics: [제네릭 이해를 위한 자료 링크]
- The History of Go Proposals: [Go 제안 시스템의 역사에 대한 자료 링크]
마무리하며:
cmp.Or
함수는 Go 개발자들에게 매우 유용한 도구가 될 것입니다.특히 조건부 값 선택이 필요한 상황에서 코드를 더욱 간결하고 명확하게 작성할 수 있도록 도와줄 것입니다.
'Go' 카테고리의 다른 글
Go 1.23 iter 패키지 완전 정복 (0) 2024.08.24 Go 1.23 이터레이터 완벽 정리 (0) 2024.08.20 Go 1.22의 새로운 기능: slices.Concat (0) 2024.07.29 Go 1.22의 새로운 기능: reflect.TypeFor (0) 2024.07.29 Go 1.23의 숨겨진 보석: reflect.Value.Seq와 reflect.Value.Seq2 (0) 2024.07.29