Примечание: Python's to_bytes
может принимать любые произвольные length
. Если вы хотите преобразовать значение в его собственный размер (например, 1 байт для Int8
, 2 байта для Int16
, 4 байта для Int32
и т. Д.), Ознакомьтесь с типами числа Swift туда и обратно в/ из данных и Как преобразовать данные в типы типа Doubles, Ints и Strings в Swift?
Для произвольной длины с расширением знака (для отрицательных чисел)Вы можете использовать & 255
для извлечения байта самого низкого порядка и >> 8
для многократного смещения значения вправо на 8 бит в цикле для вычисления байтов. (Здесь я использовал map
для генерации массива байтов). Затем используйте reversed()
, чтобы поместить их в нужный порядок байтов :
var i = 5
let len = 4
let arr: [UInt8] = (0..<len).map { _ in
let byte = UInt8(i & 255)
i >>= 8
return byte }
.reversed()
print(arr)
Выход:
[0, 0, 0, 5]
Примечания:
>>=
расширит знак отрицательное число, поэтому -5
даст ожидаемый результат дополнения до 2: [255, 255, 255, 251]
. - Явный ввод
arr
как [UInt8]
гарантирует, что arr
равен [UInt8]
, а не ReversedCollection<Array<UInt8>>
и , это помогает Swift в определении типа возврата map
. - Для порядка little endian удалите
reversed()
и просто используйте результат map
.
Реализация toBytes(length:bigEndian:)
как extension
из Int
:
Это можно добавить как расширение к Int
, чтобы дополнительно имитировать поведение метода to_bytes
Python:
extension Int {
func toBytes(length: Int, bigEndian: Bool = true) -> [UInt8] {
var i = self
let bytes: [UInt8] = (0..<length).map { _ in
let byte = UInt8(i & 255)
i >>= 8
return byte
}
return bigEndian ? bytes.reversed() : bytes
}
}
Примеры:
print(5.toBytes(length: 4))
[0, 0, 0, 5]
print((-5).toBytes(length: 4))
[255, 255, 255, 251]
print(5.toBytes(length: 8))
[0, 0, 0, 0, 0, 0, 0, 5]
print(5.toBytes(length: 8, bigEndian: false))
[5, 0, 0, 0, 0, 0, 0, 0]
Расширение toBytes
для работы с любым Int
типом
Просто безстремление FixedWidthInteger
вместо Int
делает эту работу для всех типов Int
и UInt
, за исключением Int8
, который неправильно обрабатывает расширение знака. Явная проверка этого типа и преобразование его в Int
решает эту проблему.
extension FixedWidthInteger {
func toBytes(length: Int, bigEndian: Bool = true) -> [UInt8] {
if self is Int8 {
return Int(self).toBytes(length: length, bigEndian: bigEndian)
}
var i = self
let bytes: [UInt8] = (0..<length).map { _ in
let byte = UInt8(i & 255)
i >>= 8
return byte
}
return bigEndian ? bytes.reversed() : bytes
}
}
Примеры:
print(Int8(-5).toBytes(length: 10))
print(Int16(-5).toBytes(length: 10))
print(Int32(-5).toBytes(length: 10))
print(Int64(-5).toBytes(length: 10))
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 251]
print(Int8(5).toBytes(length: 10))
print(Int16(5).toBytes(length: 10))
print(Int32(5).toBytes(length: 10))
print(Int64(5).toBytes(length: 10))
print(UInt8(5).toBytes(length: 10))
print(UInt16(5).toBytes(length: 10))
print(UInt32(5).toBytes(length: 10))
print(UInt64(5).toBytes(length: 10))
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
print(UInt64.max.toBytes(length: 10))
[0, 0, 255, 255, 255, 255, 255, 255, 255, 255]