0

我想访问一个现有的 UInt64 数组,就好像它是一个 Int8 数组一样。关键要求是效率——我不想复制或重新分配数据,只想直接访问。我不想要副作用(例如,我希望在执行此代码块后能够继续使用 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) {

这是正确的方法吗?如果是这样,为什么我会收到致命错误?

4

2 回答 2

1

感谢@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($0.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]
    }
于 2019-04-11T23:34:06.337 回答
1

我认为问题在于您不能按照文档中的注释直接绑定到不同的类型:

仅使用此方法将缓冲区的内存重新绑定到与当前绑定的 Element 类型具有相同大小和步幅的类型。要将内存区域绑定到不同大小的类型,请将缓冲区转换为原始缓冲区并使用 bindMemory(to:) 方法。

如果 bytes 是您所追求的,那么最快的路线是:

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

}
于 2019-04-11T20:54:27.117 回答