protocol EmptyInitializable {
init()
}
@propertyWrapper
struct PropertyWrapper: EmptyInitializable {
let wrappedValue: Int
init(_ wrappedValue: Int = 0) {
self.wrappedValue = wrappedValue
}
}
// This one lools redundent
extension PropertyWrapper {
public init() {
wrappedValue = 0
}
}
为什么我们需要底部的扩展?为什么编译器不能直接弄清楚
struct PropertyWrapper
已经符合 protocol EmptyInitializable
的要求?看起来好丑啊……
附注我相信它以前确实在类似的情况下起作用过。
编译器不降低
init(_ wrappedValue: Int = 0) {
self.wrappedValue = wrappedValue
}
到
init(_ wrappedValue: Int) {
self.wrappedValue = wrappedValue
}
init() {
self.init(0)
}
因为除其他原因外,编译器必须为每个可选参数生成的重载数量呈指数增长。对于具有 5 个可选参数的方法,编译器需要生成 32 个不同的签名。
话虽如此,
PropertyWrapper
显然不符合EmptyInitializable
。
实际发生的情况是只有一个重载,但对于每个可选参数,都会生成一个 thunk 来计算该参数的值。
init(_ wrappedValue: Int) {
self.wrappedValue = wrappedValue
}
func defaultValueForArgument0OfInit() {
return 0
}
还有一些元数据告诉编译器在调用者未提供所有参数时生成对该 thunk 的调用。呼叫
PropertyWrapper()
降低至 PropertyWrapper(defaultValueForArgument0OfInit())
。你可以在godbolt.org中看到编译后的代码。
如果您通过协议调用
init
,则该调用是动态调度的,因此编译器甚至不知道将调用哪个实现,更不用说是否需要传递可选参数的默认值。
当然,编译器可以通过其他方式设计来实现这一点,但是问为什么它没有以这些方式设计,并不能真正回答,除非你非常具体。
旁注:由于您只是为无需参数即可初始化的类型创建了一个协议,因此我建议阅读协议不仅仅是语法袋。