为何协议扩展可为变量赋值实例,而协议本身不行?
为什么协议里不能给变量赋值实例,但协议扩展可以?
这个问题其实戳中了Swift里协议和协议扩展最核心的本质区别——一个是抽象约定,一个是具体实现载体,我给你掰扯清楚:
协议本身是“抽象蓝图”,只负责定规则,不写具体逻辑
协议的作用是给遵守它的类型定一个“必须遵守的规矩”:比如你得有个什么类型的变量,这个变量得支持读或者读写。但它本身不是一个能存储状态、执行代码的实体。你要是在协议里直接给变量赋值实例,相当于你在“合同”里直接写了“我已经把活干了”,这不符合协议的定位——协议只说“你得有这个东西”,至于这个东西怎么初始化、怎么修改,那是遵守协议的类/结构体/枚举自己的事。协议扩展是“默认实现载体”,可以写具体的执行逻辑
协议扩展的设计目的就是给所有遵守协议的类型提供通用的默认行为。这里面你可以写具体的方法、给变量赋值的逻辑——因为扩展里的代码是实实在在能被执行的。比如你在扩展里写个方法给变量赋新值,所有遵守协议且没自己实现这个方法的类型,都会自动用上这个默认逻辑。和类扩展的区别?本质是类本身就是具体类型
类本身已经是有自己状态和实现的具体类型,类扩展只是给它加新功能,不能覆盖原有存储属性的初始化逻辑——这和协议的情况完全不同:协议是抽象的,没有自己的状态;类是具体的,本身就带着状态,所以扩展的行为逻辑自然不一样。
举个简单的代码例子你就懂了:
// 协议里只能定义规则,不能直接赋值 protocol UserProtocol { var username: String { get set } // 这里写 username = "Guest" 会直接报错,因为协议不允许写具体实现 } // 协议扩展里可以写具体的赋值逻辑 extension UserProtocol { func resetToGuest() { username = "Guest" // 这里完全合法,因为这是具体的方法实现 } } // 遵守协议的类,自己实现存储属性 class AppUser: UserProtocol { var username: String = "MyName" } let user = AppUser() user.resetToGuest() print(user.username) // 输出 "Guest"
简单总结:协议管“要做什么”,协议扩展管“默认怎么做”,这就是为什么前者不能赋值实例,后者可以的核心原因。
内容的提问来源于stack exchange,提问作者Mohammed Ali Khaled
相关产品推荐
相关产品推荐

