Swiftでビットパターンを維持した状態で整数型を変換するには、次のイニシャライザを使用します。
init<T>(truncatingIfNeeded source: T) where T : BinaryInteger
これを使って、符号無し整数と符号有り整数との間で変換できます。例えば、UInt8で0x00, 0x7F, 0x80, 0xFFは10進数では次のようになります。
| 16進数 | UInt8での10進数 |
|---|---|
| 0x00 | 0 |
| 0x7F | 127 |
| 0x80 | 128 |
| 0xFF | 255 |
同じ値がInt8では次のようになります。
| 16進数 | Int8での10進数 |
|---|---|
| 0x00 | 0 |
| 0x7F | 127 |
| 0x80 | -128 |
| 0xFF | -1 |
Playgroundで次のように入力して実行すると、期待した変換ができることが確認できます。
let u1 = UInt8(0x00)
let u2 = UInt8(0x7F)
let u3 = UInt8(0x80)
let u4 = UInt8(0xFF)
let i1 = Int8(truncatingIfNeeded: u1)
let i2 = Int8(truncatingIfNeeded: u2)
let i3 = Int8(truncatingIfNeeded: u3)
let i4 = Int8(truncatingIfNeeded: u4)

引数のラベルを指定しないと次のイニシャライザが使われます。
init<T>(_ source: T) where T : BinaryInteger
このイニシャライザでも変換できますが、範囲外の値のときにエラーになります。具体的には、UInt8からInt8への変換では、128以上の値でエラーとなります。
次のコードをPlaygroundで実行してください。
let u1 = UInt8(0x00)
let u2 = UInt8(0x7F)
let u3 = UInt8(0x80)
let u4 = UInt8(0xFF)
let i1 = Int8(u1)
let i2 = Int8(u2)
let i3 = Int8(u3)
let i4 = Int8(u4)
すると、次のようにコンソールに出力され、u3からInt8を作るときにエラーになります。
Swift/Integers.swift:3564: Fatal error: Not enough bits to represent the passed value

init(truncatingIfNeeded:)は数値のビットパターンを維持したままタイプを変換するので成功します。UInt8の128とInt8の-128はどちらも2進数では10000000です。
init(_ source:)は数値を解釈するので範囲外となってしまいます。Int8の取り得る値は-128以上127以下です。u3は128なので範囲外となります。
関連性が高い記事












