Swift中函数与闭包本质相似,为何无法在闭包中使用实例成员?
Swift闭包类型属性无法访问实例成员的原因
先看问题中的代码:
struct Account { var aName:String var aType:String var aNo:Int init(aName: String, aType: String, aNo: Int) { self.aName = aName self.aType = aType self.aNo = aNo } /* func display() { print("AccountName:\(aName) AccountType:\(aType) AccountNumber:\(aNo)") } */ var display = { print("AccountName:\(aName) AccountType:\(aType) AccountNumber:\(aNo)") } }
问题
在Swift中,函数与闭包的本质相似,但为何无法在上述代码的闭包类型属性display中直接访问Account结构体的实例成员aName、aType和aNo呢?
原因解析
属性归属的核心差异
你声明的display是类型属性(结构体中直接用var声明的存储型属性默认属于整个类型,而非单个实例),而aName、aType、aNo是实例成员——只有创建Account的具体实例时,这些成员才会分配内存、拥有具体值。类型属性在类型加载阶段就会初始化,此时没有任何实例存在,自然找不到这些仅属于实例的成员。实例方法与闭包的绑定逻辑不同
注释里的display()是实例方法,它的调用必须依赖某个Account实例,调用时Swift会自动把该实例的self绑定到方法中,所以方法里能直接访问实例成员。但你写的闭包是类型属性,它没有绑定到任何实例,也不会自动捕获self,因此无法访问只有实例才有的成员。闭包捕获的上下文限制
就算你想让闭包访问实例成员,作为类型属性的闭包也做不到——因为它属于整个类型,要是强行捕获self,要么会导致循环引用,要么逻辑上根本不成立(self代表单个实例,而类型属性不属于任何实例)。
修正方案
如果想让闭包能访问实例成员,把它改成实例属性即可,同时需要显式捕获self:
struct Account { var aName:String var aType:String var aNo:Int init(aName: String, aType: String, aNo: Int) { self.aName = aName self.aType = aType self.aNo = aNo } // 实例属性闭包,通过捕获self访问实例成员 var display: () -> Void { { [self] in print("AccountName:\(aName) AccountType:\(aType) AccountNumber:\(aNo)") } } }
当然,最简洁的方式还是用实例方法,因为Swift已经帮你处理好了self的绑定逻辑,不需要手动写捕获列表。
内容的提问来源于stack exchange,提问作者Rutwik Thorat
相关产品推荐
相关产品推荐

