我有Equatable
班
class Item: Equatable {
var value: AnyObject?
var title: String
init(title: String, value: AnyObject?) {
self.title = title
self.value = value
}
//Equatable
public static func ==(lhs: Item, rhs: Item) -> Bool {
return ((lhs.title == rhs.title) && (lhs.value === rhs.value))
}
}
但我希望将try value
转换为Equatable,以便获得软等同的结果
if let lValue = lhs.value as? Equatable, // Error
let rValue = rhs.value as? Equatable { // Error
valueEq = (lValue == rValue)
} else {
valueEq = (lhs.value === rhs.value)
}
此代码捕获有关Generic Equatable
的编译错误
我怎么能为这个班做正确的Equatable?
UPD
我想在我的故事板中使用Item
中的UITableViewCell
。我不能创建通用UITableViewCell
。如果我尝试将Item作为Generic<T: Equatable>
类,我将被迫在我的单元格中指定类型,
var items: [Item<OnlyThisHashableClass>]
但我想在单元格中使用Item中的任何对象
答案 0 :(得分:2)
您无法将AnyObject
投射到Equatable
。
您可以做的是将Item
定义为value
,Wrapped
必须为Equatable
的通用:
class Item<Wrapped: Equatable> {
var title: String
var value: Wrapped
init(title: String, value: Wrapped) {
self.title = title
self.value = value
}
}
extension Item: Equatable {
static func ==(lhs: Item, rhs: Item) -> Bool {
return lhs.title == rhs.title && lhs.value == rhs.value
}
}
而且,让我们假设你有一些类Foo
,(a)是不等的; (b)是你要用Item
包裹的东西; (c)你真的想在身份运算符===
的基础上将它们定义为等同的。 (我承认,我发现这个概念,你称之为“软等于”相当令人不安的概念,但我不会在这里讨论。)
无论如何,你可以在身份运算符的基础上使你的班级Foo
相等:
extension Foo: Equatable {
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs === rhs
}
}
或者,如果您需要为许多类执行此操作,您甚至可以拥有此身份相等的协议,然后您的非等同类可以符合:
protocol IdentityEquatable: class, Equatable { }
extension IdentityEquatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs === rhs
}
}
然后,您希望在Item
中包装的非Equatable
的任何类都可以采用此标识等同的行为,每行只有一行代码:
extension Foo: IdentityEquatable { }
extension Bar: IdentityEquatable { }
extension Baz: IdentityEquatable { }
顺便说一下,SE-0143已被批准,虽然还不是该语言的一部分,但在未来的Swift版本中提供了条件一致性的承诺,即:
class Item<Wrapped> {
var title: String
var value: Wrapped
init(title: String, value: Wrapped) {
self.title = title
self.value = value
}
}
extension Item: Equatable where Wrapped: Equatable {
static func ==(lhs: Item, rhs: Item) -> Bool {
return lhs.title == rhs.title && lhs.value == rhs.value
}
}
在这种情况下,Item
当且仅当Equatable
值为Wrapped
时才为Equatable
。这还不是该语言的一部分,但看起来它将在未来的版本中。对于这个问题,这是一个优雅的解决方案(尽管不是,不可否认,你的“软等同”的想法)。
答案 1 :(得分:1)
简单方法 - 类保持NonGeneric,Generic only init
,并在GenericInit中创建isEquals方法
class FieldItem: CustomStringConvertible, Equatable {
let value: Any?
let title: String
private let equals: (Any?) -> Bool
init<Value: Equatable>(title: String, value: Value?) {
func isEquals(_ other: Any?) -> Bool {
if let l = value, let r = other {
if let r = r as? Value {
return l == r
} else {
return false
}
} else {
return true
}
}
self.title = title
self.value = value
self.equals = isEquals
}
//CustomStringConvertible
var description: String { get { return title } }
//Equatable
public static func ==(lhs: FieldItem, rhs: FieldItem) -> Bool {
return ((lhs.title == rhs.title) && lhs.equals(rhs.value))
}
}