AnyObject 尝试转换为 Equatable
AnyObject try cast to Equatable
我有一个Equatable
class
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 var value
转换为 Equatable,以便获得软 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)
}
This code catch compilation error about Generic Equatable
如何为此 class 做正确的 Equatable?
UPD
我想在故事板中的 UITableViewCell
中使用我的 Item
。我无法创建通用 UITableViewCell
。如果我尝试将项目作为 Generic<T: Equatable>
class,我将被迫在我的单元格中指定类型,
var items: [Item<OnlyThisHashableClass>]
但我想对任何对象使用单元格中的项目
您不能将 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
}
}
并且,假设您有一些 class、Foo
,(a) 不可等式; (b) 是您想要包装在 Item
中的东西; (c) 您确实希望根据恒等运算符 ===
将它们定义为相等的。 (我承认,我发现你称之为 "soft equatable" 的想法相当令人不安,但我不会在这里深入探讨。)
无论如何,你可以让你的 class Foo
在身份运算符的基础上相等:
extension Foo: Equatable {
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs === rhs
}
}
或者,如果你需要对许多 classes 执行此操作,你甚至可以为这种身份平等制定一个协议,然后你的非平等 classes 可以符合那:
protocol IdentityEquatable: class, Equatable { }
extension IdentityEquatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs === rhs
}
}
然后任何 class 您想包装在 Item
中而不是 Equatable
的任何 Item
都可以采用这种身份等同的行为,每个行为只需一行代码:
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
}
}
在这种情况下,当且仅当 Wrapped
值为 Equatable
时,Item
才为 Equatable
。这还不是该语言的一部分,但看起来它会出现在未来的版本中。这是解决这个问题的一个优雅的解决方案(虽然不是,诚然,你的 "soft equatable" 想法)。
简单方法 - class 保持非通用,仅通用 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))
}
}
我有一个Equatable
class
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 var value
转换为 Equatable,以便获得软 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)
}
This code catch compilation error about Generic Equatable
如何为此 class 做正确的 Equatable?
UPD
我想在故事板中的 UITableViewCell
中使用我的 Item
。我无法创建通用 UITableViewCell
。如果我尝试将项目作为 Generic<T: Equatable>
class,我将被迫在我的单元格中指定类型,
var items: [Item<OnlyThisHashableClass>]
但我想对任何对象使用单元格中的项目
您不能将 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
}
}
并且,假设您有一些 class、Foo
,(a) 不可等式; (b) 是您想要包装在 Item
中的东西; (c) 您确实希望根据恒等运算符 ===
将它们定义为相等的。 (我承认,我发现你称之为 "soft equatable" 的想法相当令人不安,但我不会在这里深入探讨。)
无论如何,你可以让你的 class Foo
在身份运算符的基础上相等:
extension Foo: Equatable {
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs === rhs
}
}
或者,如果你需要对许多 classes 执行此操作,你甚至可以为这种身份平等制定一个协议,然后你的非平等 classes 可以符合那:
protocol IdentityEquatable: class, Equatable { }
extension IdentityEquatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs === rhs
}
}
然后任何 class 您想包装在 Item
中而不是 Equatable
的任何 Item
都可以采用这种身份等同的行为,每个行为只需一行代码:
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
}
}
在这种情况下,当且仅当 Wrapped
值为 Equatable
时,Item
才为 Equatable
。这还不是该语言的一部分,但看起来它会出现在未来的版本中。这是解决这个问题的一个优雅的解决方案(虽然不是,诚然,你的 "soft equatable" 想法)。
简单方法 - class 保持非通用,仅通用 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))
}
}