5.4.3 无符号整数类型

原文链接: https://kotlinlang.org/docs/unsigned-integer-types.html

5.4.3 无符号整数类型

除了整数类型之外,Kotlin 还提供了以下用于无符号整数的类型:

| 类型 | 大小(位) | 最小值 | 最大值 | | 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 阶段。它们随时可能发生不兼容的变化。使用需要选择启用(详见下文)。

与基本类型一样,每种无符号类型都有一个表示该类数组的对应类型:

  • UByteArray:无符号字节数组。
  • UShortArray:无符号短整数数组。
  • UIntArray:无符号整数数组。
  • ULongArray:无符号长整数数组。

与有符号整数数组一样,它们提供了与 Array 类相似的 API,而且没有装箱开销。

使用无符号数组时,你会收到一个提示该特性尚不稳定的警告。要消除该警告,请使用 @ExperimentalUnsignedTypes 注解选择启用。你的使用者是否需要显式选择启用你的 API,由你决定;但请记住,无符号数组不是稳定特性,因此使用它们的 API 可能因语言变化而被破坏。了解选择启用要求的更多内容。

区间与步进序列通过 UIntRange、UIntProgression、ULongRange 和 ULongProgression 类为 UInt 和 ULong 提供支持。这些类与无符号整数类型一样,都是稳定的。

无符号整数字面量

为了让无符号整数更易使用,你可以在整数字面量后加上后缀来指明特定的无符号类型(类似于 Float 的 F 或 Long 的 L):

  • 字母 u 和 U 表示无符号字面量,但不指定具体类型。如果没有提供期望类型,编译器会根据字面量的大小使用 UInt 或 ULong:
1
2
3
4
5
6
    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 明确指定该字面量应为无符号长整数:
1
    val a = 1UL // ULong, even though no expected type provided and the constant fits into UInt

使用场景

无符号数的主要用途是利用整数的完整位宽来表示正数。例如,表示无法放入有符号类型的十六进制常量,比如 32 位 AARRGGBB 格式的颜色:

1
2
3
data class Color(val representation: UInt)

val yellow = Color(0xFFCC00CCu)

你可以用无符号数初始化字节数组,而不必显式写 toByte() 字面量转换:

1
val byteOrderMarkUtf8 = ubyteArrayOf(0xEFu, 0xBBu, 0xBFu)

另一个使用场景是与原生 API 的互操作。Kotlin 允许表示签名中带无符号类型的原生声明。这种映射不会用有符号整数替换无符号整数,从而保持语义不变。

非目标

虽然无符号整数只能表示正数和零,但在应用领域要求非负整数的地方使用它们并不是我们的目标,例如用作集合大小或集合索引值的类型。

原因有几点:

  • 使用有符号整数有助于检测意外的溢出并提示错误情况,例如空列表的 List.lastIndex 为 -1。
  • 无符号整数不能被视为有符号整数的取值受限版本,因为它们的取值区间并不是有符号整数区间的子集。有符号整数和无符号整数互不为对方的子类型。