在 Swift 中做或假的"类型双关语"是一种优雅的方式



在Swift中写作时,我有一个特定的需求,可能是类型双关的候选者。我正在从磁盘映像中读取文件,这些文件位于512字节的连续扇区中。文件从磁盘上以Data结构的形式出现,它可以很容易地转换为字节数组和/或512字节的DataSlices,而不需要复制。

到目前为止,一切都很好!文件可以快速表示为包含512个UInt8单元的数组的集合。但是,一些磁盘扇区(通常包含元数据(最好作为256个UInt16项处理。理想情况下,我希望能够以任何一种方式引用内存中的扇区,而不需要任何复制。

现在,我正在采取一种简单的方法,将一个扇区(需要两个副本(复制到以下内容中:

struct Sector {
let bytes: [UInt8]
let words: [UInt16]
. . .
init() {
self.bytes = Array(repeating: 0, count: 512)
self.words = Array(repeating: 0, count: 256)
. . .

然后参考CCD_ 5或CCD_。幸运的是,[UInt16]扇区比它们的字节等价物要少得多,所以这并不太糟糕;任何给定的扇区都是其中之一,我不必担心更改bytes不会更改words(尽管这是一个等待发生的事故(。

我读到的所有内容都谴责对[UInt8][UInt16]数组的攻击,Swift的"不安全"内存函数有些吓人。我正试图想出一种方法,使上面结构中的.words.bytes占用相同的内存,并希望提供一些建议。

我还在做这件事。。如果我发现有价值的东西,我会分享。

您正在寻找中描述的技术https://stackoverflow.com/a/38024025/341994.将数据保存在data中,并根据需要将其作为UInt8或UInt16的数组进行访问。(实际上,Data是UInt8的数组,所以当你想把它看作UInt16的数组时,你只需要做任何特别的事情。(示例:

extension Data {
init<T>(fromArray values: [T]) {
self = values.withUnsafeBytes { Data($0) }
}
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
_ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
return array
}
}
let eights : [UInt8] = [1,2,3,4]
let data = Data(fromArray:eights)
let sixteens = data.toArray(type: UInt16.self)
print(sixteens) // 513, 1027

这是正确的答案,假设顺序正确;

  • 0b00000001为1
  • 0b00000010为2

因此,假设低字节高字节:

  • 0b0000001000000001为513

将其移动到类型中!

struct Sector<Datum: FixedWidthInteger> {
let data: [Datum]
init() {
data = .init(repeating: 0, count: 0x1000 / Datum.bitWidth)
}
}
typealias Byte = UInt8
typealias Word = UInt16
Sector<Byte>().data.count  // 512
Sector<Word>().data.count  // 256

最新更新