1. 概要

ドメインモデルで正の数のみを表す必要がある場合があります。 Kotlin 1.3 以降、Kotlinはこの要件に対応するために符号なし整数をサポートしています。

この短いチュートリアルでは、Kotlinでの符号なし整数の宣言と使用について理解します。

2. 符号なし整数

Kotlin 1.3では、実験的な機能として符号なし整数が導入されました。 現在、Kotlinは次の符号なしタイプのみをサポートしています。

  • kotlin.UByte は、符号なし8ビット整数(0〜255)です。
  • kotlin.UShort は、符号なし16ビット整数(0 – 65535)です。
  • kotlin.UInt は、符号なし32ビット整数(0〜2 ^ 32 – 1)です。
  • kotlin.ULong は、符号なし64ビット整数(0〜2 ^ 64 -1)です。

これらの符号なしタイプに数値リテラルを割り当てるために、Kotlinはfloatsの場合と同様の新しいu/Uサフィックスを提供します。 たとえば、ここでは、いくつかのリテラルを符号なしデータ型に割り当てています。

val uByte: UByte = 42u 
val uShort: UShort = 42u 
val uInt: UInt = 42U 
val uLong: ULong = 42u

上に示したように、リテラルを符号なし整数としてタグ付けするには、uまたはUで十分です。 宣言されたタイプは、正確な変数タイプを決定します。 たとえば、最初の例では、“ 42u” literalは符号なしUInt、ですが、宣言されたタイプはUByteです。 したがって、リテラル値はUByteに変換されます。

もちろん、型を省略すると、コンパイラはリテラル値のサイズに基づいてUIntまたはULongを推測します。

val inferredUInt = 42U 
val inferredULong = 0xFFFF_FFFF_FFFFu

コンパイラーは、両方のタイプが省略されているため、それらを推測する必要があります。 最初の例では、42が UInt 内に収まるため、推測されるタイプはUIntになります。 逆に、2番目の値は UInt 容量よりも大きいため、推測されるタイプはULongです。

また、数値リテラルをULongとしてuLサフィックスで明示的にタグ付けすることも可能です。

val explicitULong = 42uL

さらに、符号なし整数は、インラインクラスと呼ばれるKotlin1.3の別の実験的機能を使用して実装されていることに言及する価値があります。

3. 実験的特徴

この記事の執筆時点では、この新しい符号なし整数機能は実験段階にあります。 したがって、コードでそれらを使用すると、コンパイラは将来の互換性のない変更の可能性について警告を発行します。

This declaration is experimental and its usage should be marked with '@kotlin.ExperimentalUnsignedTypes' or '@OptIn(kotlin.ExperimentalUnsignedTypes::class)'

幸いなことに、警告自体は非常にわかりやすいものです。 したがって、この実験的な機能を確実に使用できる場合は、囲んでいるクラスまたは関数にExperimentalUnsignedTypesまたはOptIn(kotlin.ExperimentalUnsignedTypes :: class)で注釈を付けることができます。

@ExperimentalUnsignedTypes 
fun main() { 
    // use unsigned integers here without warning 
}

Kotlinコンパイラがこれらのアノテーションを確認すると、警告をスキップします。

Kotlin 1.5 以降、 UInt ULong UByte 、およびUShort符号なし整数型は安定しています。 これらのタイプの操作、およびそれらの範囲と進行についても同じことが言えます。 したがって、オプトインなしで利用でき、実際のプロジェクトで安全に使用できます。 一方、符号なし型の配列はまだベータ段階です。

4. 符号なし配列

単一の符号なし整数に加えて、符号なしコンポーネントを使用して配列を作成することができます。 実際のところ、符号なし整数ごとに、対応する配列型があります。 具体的には、 UByteArray UShortArray UIntArray ULongArrayです。

符号なし整数コンポーネントを含む配列を作成するには、それらのコンストラクターを使用できます。

val ba = UByteArray(42)

ここでは、長さが42のUByteの配列を作成しています。 同様に、他の署名されていない配列は、同じ署名を持つコンストラクターを提供します。

コンストラクターに加えて、 ubyteArrayOf() factoryメソッドを使用して、初期要素を持つ配列を作成できます。

val ba2 = ubyteArrayOf(42u, 43u)

ここでは、2つの要素を持つUByteの配列を作成しています。 同様に、Kotlinは、他の符号なし配列にも u * ArrayOf()構文を使用したファクトリメソッドを提供します。

5. 符号なしタイプの操作

符号なし整数は、符号付き整数と同じ一連の演算をサポートします。 たとえば、2つの符号なし型を一緒に追加し、それらに対して左シフトを実行し、他の多くの一般的な算術演算を実行できます。

assertEquals(3u, 2u + 1u)
assertEquals(16u, 2u shl 3)

同様に、符号なし配列は、符号付き配列と同じAPIを提供します。

uintArrayOf(42u, 43u).map { it * it }.forEach { println(it) }

さらに、符号付き整数を符号なし整数に、またはその逆に変換することができます。

val anInt = 42 
val converted = anInt.toUInt()

明らかに、符号なしデータ型ごとに、Kotlinは toU *()メソッドを提供します。

符号付き整数の最上位ビットは符号ビットであることに注意してください。 それどころか、そのビットは符号なし整数の通常のビットです。 したがって、負の符号付き整数を符号なし整数に変換するのは難しい場合があります。

assertEquals((255).toUByte(), (-1).toUByte())
assertEquals((65535).toUShort(), (-1).toUShort())
assertEquals(4294967295u, (-1).toUInt())
assertEquals(18446744073709551615uL, (-1L).toULong())

-1整数のバイナリ表現は、「1111 1111 1111 1111 11111111111111111」です。  したがって、UByte、UShort、UInt、およびULongで可能な最大数に変換されます。 。 したがって、たとえばIntを対応するUIntに変換する場合、常に同じ数になるとは限りません。 同様に、UIntIntに変換する場合も同様です。

assertEquals(-1, (4294967295u).toInt())

符号付き配列を符号なし配列に変換することもできます。

val toUIntArray = intArrayOf(-1, -2).toUIntArray()

6. 結論

このチュートリアルでは、Kotlinの符号なし整数について理解しました。 そのようなデータ型を宣言し、それらを操作し、そしてもちろん、対応する署名された型からそれらを作成するいくつかの異なる方法を見ました。 また、そのようなデータ型から配列を作成する方法も確認しました。

いつものように、すべての例はGitHubから入手できます。