부호 없는 정수 타입
부호 없는 정수 타입
정수 타입에 더해, Kotlin은 부호 없는 정수를 위한 타입도 제공해요.
출처: Kotlin 공식 문서
본문
| Type | Size (bits) | Min value | Max value |
|---|---|---|---|
UByte |
8 | 0 | 255 |
UShort |
16 | 0 | 65,535 |
UInt |
32 | 0 | 4,294,967,295 (232 - 1) |
ULong |
64 | 0 | 18,446,744,073,709,551,615 (264 - 1) |
부호 없는 타입은 부호 있는 대응 타입이 지원하는 연산을 대부분 지원해요.
부호 없는 숫자는 같은 폭의 부호 있는 대응 타입을 담는 저장 프로퍼티 하나를 가진 인라인 클래스로 구현돼요. 부호 없는 타입과 부호 있는 타입 사이를 변환할 때는, 모든 함수 호출과 연산이 새 타입을 지원하도록 코드를 업데이트해야 하니 유의하세요.
부호 없는 배열과 범위
부호 없는 배열과 그에 대한 연산은 베타(Beta) 상태예요. 호환되지 않는 방식으로 언제든 바뀔 수 있으니 opt-in이 필요합니다 (자세한 내용은 아래 참고).
원시 타입과 마찬가지로, 각 부호 없는 타입에는 그 타입의 배열을 나타내는 타입이 대응돼요.
UByteArray: 부호 없는 바이트의 배열.UShortArray: 부호 없는 short의 배열.UIntArray: 부호 없는 int의 배열.ULongArray: 부호 없는 long의 배열.
부호 있는 정수 배열과 마찬가지로, 박싱 오버헤드 없이 Array 클래스와 유사한 API를 제공해요.
부호 없는 배열을 사용하면 아직 안정적이지 않은 기능이라는 경고를 받아요. 그 경고를 없애려면 @ExperimentalUnsignedTypes 애너테이션으로 opt-in하면 됩니다. 클라이언트가 여러분의 API 사용 시 명시적으로 opt-in을 해야 할지는 여러분이 결정할 몫이에요. 다만 부호 없는 배열은 안정적인 기능이 아니므로, 그걸 쓰는 API는 언어가 바뀌면 깨질 수 있다는 점을 기억하세요. opt-in 요구사항에 대해 더 알아보세요.
범위와 수열은 UInt와 ULong에 대해 UIntRange, UIntProgression, ULongRange, ULongProgression 클래스로 지원돼요. 이 클래스들은 부호 없는 정수 타입과 함께 안정적이에요.
부호 없는 정수 리터럴
부호 없는 정수를 쓰기 쉽게 하려면 정수 리터럴에 특정 부호 없는 타입을 나타내는 접미사를 붙일 수 있어요 (Float의 F나 Long의 L과 비슷하게요).
u와U글자는 정확한 타입을 지정하지 않는 부호 없는 리터럴을 뜻해요. 기대 타입이 주어지지 않으면 컴파일러는 리터럴의 크기에 따라UInt나ULong을 사용해요.
val b: UByte = 1u // UByte, expected type provided
val s: UShort = 1u // UShort, expected type provided
val l: ULong = 1u // ULong, expected type provided
val a1 = 42u // UInt: no expected type provided, constant fits in UInt
val a2 = 0xFFFF_FFFF_FFFFu // ULong: no expected type provided, constant doesn't fit in UInt
uL과UL은 리터럴이 부호 없는 long이어야 함을 명시해요.
val a = 1UL // ULong, even though no expected type provided and the constant fits into UInt
사용 사례
부호 없는 숫자의 주된 용도는 정수의 전체 비트 범위를 양수 값을 표현하는 데 활용하는 거예요. 예를 들어 32비트 AARRGGBB 형식의 색상 같은, 부호 있는 타입에 들어가지 않는 16진수 상수를 나타낼 때요.
data class Color(val representation: UInt)
val yellow = Color(0xFFCC00CCu)
명시적인 toByte() 리터럴 캐스트 없이 바이트 배열을 초기화하는 데도 부호 없는 숫자를 쓸 수 있어요.
val byteOrderMarkUtf8 = ubyteArrayOf(0xEFu, 0xBBu, 0xBFu)
또 다른 사용 사례는 네이티브 API와의 상호 운용이에요. Kotlin은 시그니처에 부호 없는 타입을 포함한 네이티브 선언을 표현할 수 있게 해요. 이때 매핑은 부호 없는 정수를 부호 있는 것으로 대체하지 않아서 의미를 그대로 유지해요.
비목표(Non-goals)
부호 없는 정수는 양수와 0만 표현할 수 있는데, 애플리케이션 도메인이 음이 아닌 정수를 요구하는 곳(예: 컬렉션의 크기나 컬렉션 인덱스 값)에서는 그것들을 사용하는 게 목표가 아니에요.
그 이유는 몇 가지가 있어요.
- 부호 있는 정수를 쓰면 우발적 오버플로를 감지하고 오류 조건을 신호로 알리는 데 도움이 돼요. 예를 들어 빈 리스트에서
List.lastIndex는 -1이죠. - 부호 없는 정수의 값 범위는 부호 있는 정수 범위의 부분집합이 아니기 때문에, 부호 없는 정수를 부호 있는 정수의 범위 제한 버전으로 취급할 수 없어요. 부호 있는 정수와 부호 없는 정수는 서로의 서브타입이 아니에요.
더 알아보기 (Learn more)
- 정수 타입 문서에서 부호 있는 정수와 리터럴을 확인하세요.
- 인라인 클래스 문서에서 부호 없는 타입이 어떻게 구현되는지 살펴보세요.
- opt-in 요구사항 문서에서
@ExperimentalUnsignedTypes사용법을 더 알아보세요.