我目前正在Swift中编写一个可重用的UI组件,应该从Obj-C / Swift世界中使用它(这是一个混合项目)。我定义了没有任何关联类型的@objc
协议(因为@objc
协议不允许使用这些类型)。在组件中的一种方法中,我需要将协议存储为类型,并且需要找到特定条目的索引,这与以下内容类似-
func select<T: Itemable>(_ item: T) {
guard let itemIndex = items.index(of: item) else {
return
}
//more stuf
}
其中items
是Itemable
(协议)类型的数组。
但是,由于equatable具有静态要求,因此我收到错误消息,说我不能将其用作符合Equatable的类型。Itemable
定义如下-
@objc protocol Itemable {
//methods and properties
}
此外,也不知道如何使其符合等值。显然,以下内容可以帮助但不确定原因-
func ==<T: <Itemable>>(lhs: T, rhs: T) -> Bool {
return lhs.aProperty == rhs.aProperty
}
在我看来,可能需要擦除类型,但不确定如何执行此操作。
您不能使@objc
类型符合Equatable。平等的有自我要求。 Objective-C协议无法表达自我要求。
您的==
函数可用,但不会导致类型符合Equatable。这仅表示您可以评估item == item
。但是,由于Itemable不符合Equatable,因此无法调用items.contain(item)
。您可以执行的操作是调用items.contains{$0 == item}
,因为这只需要==
功能,而不是等值的。当然,如果需要,可以为.contains
实现自定义[Itemable]
方法。但这仍然不是平等的。
例如,我相信您想完全摆脱==
,并使用此方法:
guard let itemIndex = items.index(where: { $0.aProperty == item.aProperty }) else {
如果您经常这样做,当然可以在[Itemable]
上添加扩展名(未经测试):
extension Array where Element: Itemable {
func index(of element: Element) -> Int? {
index(where: { $0.aProperty == item.aProperty })
}
}
那么您的原始代码就可以了。
与您的问题有点无关:这可能是简化的代码,但请务必注意==
的这种实现。首先,==
应该始终测试所有可见属性。例如,如果aProperty
仅是ID,则这是实现==
的危险方式。当两个条件相等时(在ObjC和Swift中),它们在所有上下文中都可以互换。如果您关心自己拥有的那个,那它们并不是真正的“平等”。
此外,当两个事物相等时,它们应该具有相同的哈希值(并且如果它们是相等的,它们必须则具有相同的哈希值)。
请参阅Conforming to the Equatable Protocol中的文档以获取规则。尽管从技术上讲==
并不表示可等于,但如果您不等于可等于,则使用它会令人困惑。