Swift 中协议一致性的冗余扩展

问题描述 投票:0回答:1
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
的要求?看起来好丑啊……

附注我相信它以前确实在类似的情况下起作用过。

swift initialization protocols swift-extensions
1个回答
0
投票

编译器不降低

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
,则该调用是动态调度的,因此编译器甚至不知道将调用哪个实现,更不用说是否需要传递可选参数的默认值

当然,编译器可以通过其他方式设计来实现这一点,但是问为什么它没有以这些方式设计,并不能真正回答,除非你非常具体。

旁注:由于您只是为无需参数即可初始化的类型创建了一个协议,因此我建议阅读协议不仅仅是语法袋

© www.soinside.com 2019 - 2024. All rights reserved.