在没有复制或分配的 Swift 数组类型之间进行转换
Casting between Swift array types without copy or allocations
我想像访问 Int8 数组一样访问现有的 UInt64 数组。关键要求是效率——我不想复制或重新分配数据,只想直接访问。我不想要副作用(例如,我希望能够在执行此代码块后继续使用 uint64Array,正在阅读有关具有未定义副作用的重新绑定。)
我尝试使用 Swift 4.2:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBufferPointer() {
uint64Pointer in
uint64Pointer.withMemoryRebound(to: Int8.self) { // <- Error occurs here.
int8Pointer in
int8Pointer[0] = 1
int8Pointer[1] = 2
int8Pointer[2] = 3
int8Pointer[3] = 4
}
}
但是我在运行时在以下行中遇到致命错误:
uint64Pointer.withMemoryRebound(to: Int8.self) {
这是正确的方法吗?如果是这样,为什么我会收到致命错误?
我认为问题是您不能按照文档中的注释直接绑定到不同的类型:
Only use this method to rebind the buffer’s memory to a type with the same size and stride as the currently bound Element type. To bind a region of memory to a type that is a different size, convert the buffer to a raw buffer and use the bindMemory(to:) method.
如果字节是您想要的,那么最快的路线是:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBytes { x in
x[0] = 1
x[1] = 2
x[3] = 3
x[4] = 4
}
如果您想使用其他类型,可以这样做:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBufferPointer() {
uint64Pointer in
let x = UnsafeMutableRawBufferPointer(uint64Pointer).bindMemory(to: Int32.self)
x[0] = 1
x[1] = 2
x[3] = 3
x[4] = 4
}
感谢@brindy 解决了这个问题。这是一个尽可能干净的扩展实现。
扩展名:
extension Array {
mutating func bindMutableMemoryTo<T,R>(_ type: T.Type, _ closure: (UnsafeMutableBufferPointer<T>) throws -> R) rethrows -> R {
return try self.withUnsafeMutableBytes() {
return try closure([=10=].bindMemory(to: type))
}
}
}
用法:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.bindMutableMemoryTo(Int8.self) {
int8Pointer in
int8Pointer[0] = 1 // LSB of uint64Array[0]
int8Pointer[1] = 2
int8Pointer[2] = 3
int8Pointer[3] = 4 // MSB of uint64Array[0]
}
我想像访问 Int8 数组一样访问现有的 UInt64 数组。关键要求是效率——我不想复制或重新分配数据,只想直接访问。我不想要副作用(例如,我希望能够在执行此代码块后继续使用 uint64Array,正在阅读有关具有未定义副作用的重新绑定。)
我尝试使用 Swift 4.2:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBufferPointer() {
uint64Pointer in
uint64Pointer.withMemoryRebound(to: Int8.self) { // <- Error occurs here.
int8Pointer in
int8Pointer[0] = 1
int8Pointer[1] = 2
int8Pointer[2] = 3
int8Pointer[3] = 4
}
}
但是我在运行时在以下行中遇到致命错误:
uint64Pointer.withMemoryRebound(to: Int8.self) {
这是正确的方法吗?如果是这样,为什么我会收到致命错误?
我认为问题是您不能按照文档中的注释直接绑定到不同的类型:
Only use this method to rebind the buffer’s memory to a type with the same size and stride as the currently bound Element type. To bind a region of memory to a type that is a different size, convert the buffer to a raw buffer and use the bindMemory(to:) method.
如果字节是您想要的,那么最快的路线是:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBytes { x in
x[0] = 1
x[1] = 2
x[3] = 3
x[4] = 4
}
如果您想使用其他类型,可以这样做:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBufferPointer() {
uint64Pointer in
let x = UnsafeMutableRawBufferPointer(uint64Pointer).bindMemory(to: Int32.self)
x[0] = 1
x[1] = 2
x[3] = 3
x[4] = 4
}
感谢@brindy 解决了这个问题。这是一个尽可能干净的扩展实现。
扩展名:
extension Array {
mutating func bindMutableMemoryTo<T,R>(_ type: T.Type, _ closure: (UnsafeMutableBufferPointer<T>) throws -> R) rethrows -> R {
return try self.withUnsafeMutableBytes() {
return try closure([=10=].bindMemory(to: type))
}
}
}
用法:
var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.bindMutableMemoryTo(Int8.self) {
int8Pointer in
int8Pointer[0] = 1 // LSB of uint64Array[0]
int8Pointer[1] = 2
int8Pointer[2] = 3
int8Pointer[3] = 4 // MSB of uint64Array[0]
}