gpt4 book ai didi

swift - withUnsafeBytes + 通用类型行为

转载 作者:搜寻专家 更新时间:2023-10-31 08:28:14 25 4
gpt4 key购买 nike

我有一个函数可以让我使用通用类型从二进制文件中读取数字(Integer、Double 等)。例如,如果我期望 Int64,il 将读取 8 个字节...

// A simple function that read n bytes from a FileHandle and returns
// the data

public func read(chunkSize: Int) -> Data {
return self.handle!.readData(ofLength: chunkSize)
}

// A function that reads the proper amount of bytes specified
// by the return type which in my case would be an integer

public func readNumber<I>() -> I? {
let data: Data = self.read(chunkSize: MemoryLayout<I>.size)
if data.count == 0 {
return nil
}
return data.withUnsafeBytes { $0.pointee }
}

readNumber 无缘无故随机返回 nil。不是来自 count 检查,而是来自最后一行。

然而,当我转换为 I 时它完美地工作:

像我一样返回 data.withUnsafeBytes { $0.pointee }

这是为什么?

编辑:

我使用 Playgrounds 复制了这个:

class Test {

public func read(chunkSize: Int) -> Data {
return Data(repeating: 1, count: chunkSize)
}

public func readNumber<T>() -> T? {
let data: Data = read(chunkSize: MemoryLayout<T>.size)
if data.count == 0 {
return nil
}
return data.withUnsafeBytes { $0.pointee }
}

public func example() {
let value2: Double = readNumber()!
print(value2)
}
}

let test = Test()

for i in 0..<1000 {
test.example()
}

最佳答案

看来我需要更正一下我的评论。即使 Swift 按照编程的方式始终如一地工作,当您遇到一些内存问题(例如访问越界)时,结果可能看起来随机变化。

首先为UnsafePointer准备一个魔法扩展:

extension UnsafePointer {
var printingPointee: Pointee {
print(Pointee.self) //<- Check how Swift inferred `Pointee`
return self.pointee
}
}

并稍微修改您的EDIT代码:

class Test {

public func read(chunkSize: Int) -> Data {
return Data(repeating: 1, count: chunkSize)
}

public func readNumber<T>() -> T? {
let data: Data = read(chunkSize: MemoryLayout<T>.size)
if data.count == 0 {
return nil
}
print(T.self) //<- Check how Swift inferred `T`
return data.withUnsafeBytes { $0.printingPointee }
}

public func example() {
let value2: Double = readNumber()!
print(value2)
}
}

let test = Test()

for _ in 0..<1000 {
test.example()
}

输出:

Double
Optional<Double>
7.748604185489348e-304
Double
Optional<Double>

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

有多少对DoubleOptional<Double>显示似乎是随机的,但这种行为的原因很清楚。

在这一行return data.withUnsafeBytes { $0.printingPointee } , Swift 推断出 $0 的类型作为UnsafePointer<Optional<Double>> .

在当前的 Swift 实现中,Optional<Double>占用内存9个字节:

print(MemoryLayout<Optional<Double>>.size) //-> 9

所以,$0.pointee从指针开始访问 9 个字节,尽管指针指向 8 字节的区域:

|+0|+1|+2|+3|+4|+5|+6|+7|+8|
+--+--+--+--+--+--+--+--+
01 01 01 01 01 01 01 01 ??
<-taken from the Data->

如您所知,额外的第 9 个 ( +8 ) 字节无法预测,可能看起来是随机的,这是 nil 的一个指标。在Optional<Double> .

完全相同的推理在您的代码中起作用。在你的readNumber<T>() ,返回类型明确声明为 T? ,因此,在 return data.withUnsafeBytes { $0.pointee } 行中,Swift 很自然地推断出 $0.pointee 的类型作为Double?又名 Optional<Double> .

您知道可以通过添加 as T 来控制此类型推断.

关于swift - withUnsafeBytes + 通用类型行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53181016/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com