Swift中能否区分类与typealias?如何限制二者Equatable比较?
在Swift中区分类与typealias及定制Equatable行为
嘿,这个问题问得相当精准!咱们一步步来拆解你关心的两个点:
一、Swift能直接区分类和它的typealias吗?
答案是:默认情况下不行。因为typealias本质就是原类型的“别名”,编译器会完全把它和原类型视为同一个实体。举个例子:
class MyClass {} typealias MyAlias = MyClass let obj1 = MyClass() let obj2 = MyAlias() type(of: obj1) == type(of: obj2) // 返回true,因为它们是同一个类型
如果非要区分两者,你得绕个弯,不能用单纯的typealias:
- 方案1:用包装结构体包裹原类实例,让“别名”成为一个全新的类型(推荐)
- 方案2:给原类添加额外的标记属性,用来区分是原类实例还是通过别名创建的实例
二、如何定制Equatable,禁止类与“别名”比较或让比较返回false?
根据上面的区分方案,我们有两种对应的实现方式:
方案1:用包装结构体替代typealias(从根源区分类型)
这种方式最彻底,因为包装后的“别名”是完全独立的类型,和原类互不干扰:
class MyClass: Equatable { let value: Int init(value: Int) { self.value = value } static func == (lhs: MyClass, rhs: MyClass) -> Bool { lhs.value == rhs.value } } // 用结构体包装,替代单纯的typealias struct MyAlias { let wrapped: MyClass init(value: Int) { self.wrapped = MyClass(value: value) } } // 给MyAlias实现Equatable extension MyAlias: Equatable { static func == (lhs: MyAlias, rhs: MyAlias) -> Bool { lhs.wrapped == rhs.wrapped } // 如果你想让跨类型比较返回false,就实现下面的方法 static func == (lhs: MyAlias, rhs: MyClass) -> Bool { false } static func == (lhs: MyClass, rhs: MyAlias) -> Bool { false } } // 测试效果 let original = MyClass(value: 5) let aliased = MyAlias(value: 5) original == aliased // 返回false aliased == aliased // 返回true original == MyClass(value:5) // 返回true
如果想完全禁止跨类型比较,只需要不实现上面的跨类型==方法,此时编译器会直接报错,阻止你把MyClass和MyAlias实例放在一起比较。
方案2:给原类添加标记属性(基于typealias的妥协方案)
如果一定要用typealias,只能通过给类加标记来区分实例来源,然后在Equatable逻辑里判断:
class MyClass: Equatable { let value: Int // 用这个标记区分是原类还是别名实例 private let typeIdentifier: String // 原类初始化默认用"MyClass"作为标记 init(value: Int, typeIdentifier: String = "MyClass") { self.value = value self.typeIdentifier = typeIdentifier } static func == (lhs: MyClass, rhs: MyClass) -> Bool { // 先检查标记是否一致,不一致直接返回false guard lhs.typeIdentifier == rhs.typeIdentifier else { return false } return lhs.value == rhs.value } } // 定义typealias typealias MyAlias = MyClass // 创建实例时,别名实例要传入专属标记 let original = MyClass(value: 5) let aliased = MyAlias(value: 5, typeIdentifier: "MyAlias") original == aliased // 返回false original == MyClass(value:5) // 返回true aliased == MyAlias(value:5, typeIdentifier: "MyAlias") // 返回true
这种方式的缺点是需要手动传入标记,容易因为疏忽导致标记错误,所以更推荐第一种包装结构体的方案。
内容的提问来源于stack exchange,提问作者cweber105
相关产品推荐
相关产品推荐

