我知道如何在java中做到这一点(参见here),但我找不到java的ByteBuffer的快速等价物,因此找不到它的.putDouble(double value)方法。
基本上,我正在寻找这样的函数:
func doubleToByteArray(value: Double) -> [UInt8]? {
. . .
}
doubleToByteArray(1729.1729) // should return [64, 155, 4, 177, 12, 178, 149, 234]
答案 0 :(得分:48)
typealias Byte = UInt8
func toByteArray<T>(var value: T) -> [Byte] {
return withUnsafePointer(&value) {
Array(UnsafeBufferPointer(start: UnsafePointer<Byte>($0), count: sizeof(T)))
}
}
toByteArray(1729.1729)
toByteArray(1729.1729 as Float)
toByteArray(1729)
toByteArray(-1729)
但结果与您的预期相反(因为有字节顺序):
[234, 149, 178, 12, 177, 4, 155, 64]
[136, 37, 216, 68]
[193, 6, 0, 0, 0, 0, 0, 0]
[63, 249, 255, 255, 255, 255, 255, 255]
添加了:
func fromByteArray<T>(value: [Byte], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
return UnsafePointer<T>($0.baseAddress).memory
}
}
let a: Double = 1729.1729
let b = toByteArray(a) // -> [234, 149, 178, 12, 177, 4, 155, 64]
let c = fromByteArray(b, Double.self) // -> 1729.1729
对于Xcode8 / Swift3.0:
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<T>.size) {
Array(UnsafeBufferPointer(start: $0, count: MemoryLayout<T>.size))
}
}
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
对于Xcode8.1 / Swift3.0.1
func toByteArray<T>(_ value: T) -> [UInt8] {
var value = value
return withUnsafeBytes(of: &value) { Array($0) }
}
func fromByteArray<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBytes {
$0.baseAddress!.load(as: T.self)
}
}
答案 1 :(得分:6)
嗯,这并不容易,但现在是:
func doubleToByteArray(value: Double) -> [UInt8] {
let count = sizeof(Double)
var doubles: [Double] = [value]
let data = NSData(bytes: doubles, length: count)
var result = [UInt8](count: count, repeatedValue: 0)
data.getBytes(&result, length: count)
return result
}
谨慎使用。
答案 2 :(得分:4)
这是我对原始解决方案的更新版本。
/// input: array of bytes
/// -> get pointer to byte array (UnsafeBufferPointer<[Byte]>)
/// -> access its base address
/// -> rebind memory to target type T (UnsafeMutablePointer<T>)
/// -> extract and return the value of target type
func binarytotype <T> (_ value: [Byte], _: T.Type) -> T
{
return value.withUnsafeBufferPointer {
$0.baseAddress!
.withMemoryRebound(to: T.self, capacity: 1) {
$0.pointee
}
}
}
/// input type: value of type T
/// -> get pointer to value of T
/// -> rebind memory to the target type, which is a byte array
/// -> create array with a buffer pointer initialized with the source pointer
/// -> return the resulted array
func typetobinary <T> (_ value: T) -> [Byte]
{
var mv : T = value
let s : Int = MemoryLayout<T>.size
return withUnsafePointer(to: &mv) {
$0.withMemoryRebound(to: Byte.self, capacity: s) {
Array(UnsafeBufferPointer(start: $0, count: s))
}
}
}
PS:别忘了用UInt8替换Byte。
答案 3 :(得分:4)
swift 3中的解决方案:
public func toByteArray<T>(_ value: T) -> [Byte] {
let totalBytes = MemoryLayout<T>.size
var value = value
return withUnsafePointer(to: &value) { valuePtr in
return valuePtr.withMemoryRebound(to: Byte.self, capacity: totalBytes) { reboundPtr in
return Array(UnsafeBufferPointer(start: reboundPtr, count: totalBytes))
}
}
}
答案 4 :(得分:4)
由于MemoryLayout
为您提供静态类型T
的大小,因此接受的答案很危险!
要解决此问题,您应该创建自定义协议并在其中询问Self
:
protocol ByteConvertible {}
extension ByteConvertible {
func toBytes() -> [UInt8] {
let capacity = MemoryLayout<Self>.size
var mutableValue = self
return withUnsafePointer(to: &mutableValue) {
return $0.withMemoryRebound(to: UInt8.self, capacity: capacity) {
return Array(UnsafeBufferPointer(start: $0, count: capacity))
}
}
}
}
我之前提到,接受的答案很危险,这是一个例子:
let num = UInt8(42)
MemoryLayout.size(ofValue: num) //=> 1 byte as expected
let any: Any = num
MemoryLayout.size(ofValue: any) //=> 32 bytes which is what will happen in the generic functions from the all the answers
Swift 3.0
答案 5 :(得分:1)
上面的方法可以使用Swift 2,但是,我发现了一种更简单,更快速的方法来进行这种转换,反之亦然:
func binarytotype <T> (value: [UInt8], _: T.Type) -> T
{
return value.withUnsafeBufferPointer
{
return UnsafePointer<T>($0.baseAddress).memory
}
}
func typetobinary <T> (var value: T) -> [UInt8]
{
return withUnsafePointer(&value)
{
Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>($0), count: sizeof(T)))
}
}
let a: Double = 0.25
let b: [UInt8] = typetobinary(a) // -> [0, 0, 0, 0, 0, 0, 208, 63]
let c = binarytotype(b, Double.self) // -> 0.25
我在操场上用Xcode 7.2测试了它。
答案 6 :(得分:1)
func byteArray<T>(_ value: T) -> [UInt8] {
var value = value
var initialArray = withUnsafeBytes(of: &value) { Array($0) }
initialArray.reverse()
var count = initialArray.count
while initialArray.first == 0 && count > 1 {
initialArray[0...count - 2] = initialArray[1...count - 1]
count -= 1
}
if initialArray[0] >= 128 {
var newArray = [UInt8](repeating: 0, count: count + 1)
newArray[0] = UInt8(0)
newArray[1...count] = initialArray[0...count - 1]
return newArray
} else {
return Array(initialArray[0...count - 1])
}
}