我想了解在Swift中存储在栈和堆中的内容。我有一个大概的估计:所有打印出来并显示内存地址而非具体值的对象都存储在栈中,所有打印出来作为具体值的对象都存储在堆中,这基本上取决于值类型和引用类型。我的理解完全错误吗?如果可以的话,能否提供栈/堆的可视化表示?
我想了解在Swift中存储在栈和堆中的内容。我有一个大概的估计:所有打印出来并显示内存地址而非具体值的对象都存储在栈中,所有打印出来作为具体值的对象都存储在堆中,这基本上取决于值类型和引用类型。我的理解完全错误吗?如果可以的话,能否提供栈/堆的可视化表示?
类(引用类型)是分配在堆上的,值类型(例如结构体、字符串、整数、布尔等)存储在栈中。有关更详细的答案,请参见此主题:为什么选择结构体而不是类?
protocol Vehicle {
var mileage: Double { get }
}
struct CombustionCar: Vehicle {
let mpg: Double
let isDiesel: Bool
let isManual: Bool
var fuelLevel: Double // gallons
var mileage: Double { fuelLevel * mpg }
}
struct ElectricCar: Vehicle {
let mpge: Double
var batteryLevel: Double // kWh
var mileage: Double { batteryLevel * mpge / 33.7 }
}
func printMileage(vehicle: Vehicle) {
print("\(vehicle.mileage)")
}
let datsun: Vehicle = CombustionCar(mpg: 18.19,
isDiesel: false,
isManual: false,
fuelLevel: 12)
let tesla: Vehicle = ElectricCar(mpge: 132,
batteryLevel: 50)
let vehicles: [Vehicle] = [datsun, tesla]
for vehicle in vehicles {
printMileage(vehicle: vehicle)
}
CombustionCar
和ElectricCar
对象的大小不同,但我们能够将它们混合在一个Vehicle
协议类型的数组中。这引出了一个问题:容器元素难道不需要具有相同的大小吗?如果编译器无法始终知道元素大小,它如何计算数组元素的偏移量?Existential Container
。它是一个固定大小的数据结构,作为对象的包装器。它被传递给函数调用(压入堆栈)而不是实际的结构体。
Existential Container
由五个单词组成。| |
|valueBuffer|
| |
| vwt |
| pwt |
前三个字被称为valueBuffer
,这是实际结构体存储的地方。不过,如果结构体大小大于三个字,则编译器会在堆上分配结构体,并将引用存储在valueBuffer
中:
STACK STACK HEAP
| mpge | | reference |-->| mpg |
|batteryLevel| | | | isDiesel |
| | | | | isManual |
| vwt | | vwt | | fuelLevel |
| pwt | | pwt |