Кажется, мне нужно немного исправить свой комментарий. Даже если 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>
Тема 1: Неустранимая ошибка: неожиданно обнаружен ноль при развертывании
Необязательное значение
Сколько показанных пар Double
и Optional<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?
aka Optional<Double>
.
Вы знаете, что вы можете управлять выводом этого типа, добавив as T
.