我已经定义了一个枚举来代表一个"站的选择&#34 ;;工作站由唯一的正整数定义,因此我创建了以下枚举,以允许负值表示特殊选择:
enum StationSelector : Printable {
case Nearest
case LastShown
case List
case Specific(Int)
func toInt() -> Int {
switch self {
case .Nearest:
return -1
case .LastShown:
return -2
case .List:
return -3
case .Specific(let stationNum):
return stationNum
}
}
static func fromInt(value:Int) -> StationSelector? {
if value > 0 {
return StationSelector.Specific(value)
}
switch value {
case -1:
return StationSelector.Nearest
case -2:
return StationSelector.LastShown
case -3:
return StationSelector.List
default:
return nil
}
}
var description: String {
get {
switch self {
case .Nearest:
return "Nearest Station"
case .LastShown:
return "Last Displayed Station"
case .List:
return "Station List"
case .Specific(let stationNumber):
return "Station #\(stationNumber)"
}
}
}
}
我希望将这些值用作字典中的键。声明字典会产生StationSelector不符合Hashable的预期错误。使用简单的哈希函数可以很容易地符合Hashable:
var hashValue: Int {
get {
return self.toInt()
}
}
但是,Hashable
要求符合Equatable
,我似乎无法在枚举上定义equals运算符以满足编译器。
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
编译器抱怨这是一行上的两个声明,并希望在;
之后加func
,这也没有意义。
有什么想法吗?
答案 0 :(得分:23)
来自Swift书:
没有关联值的枚举成员值(如中所述) 枚举)也可以默认使用。
但是,您的枚举确实有一个带有关联值的成员值,因此您必须手动添加Hashable
一致性。
您的实现存在的问题是,Swift中的运算符声明必须处于全局范围。
移动:
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
在enum
定义之外,它将起作用。
点击the docs了解更多信息。
答案 1 :(得分:6)
我努力尝试制作一个enum
,其关联值符合Hashable
。
我在enum
创建了Hashable
,其关联值符合Dictionary
,因此可以将其排序或用作Hashable
键,或执行其他任何操作{{1} }} 可以做。
您必须使关联的值enum
符合Hashable
,因为关联的值enums
不能包含原始类型。
public enum Components: Hashable {
case None
case Year(Int?)
case Month(Int?)
case Week(Int?)
case Day(Int?)
case Hour(Int?)
case Minute(Int?)
case Second(Int?)
///The hashValue of the `Component` so we can conform to `Hashable` and be sorted.
public var hashValue : Int {
return self.toInt()
}
/// Return an 'Int' value for each `Component` type so `Component` can conform to `Hashable`
private func toInt() -> Int {
switch self {
case .None:
return -1
case .Year:
return 0
case .Month:
return 1
case .Week:
return 2
case .Day:
return 3
case .Hour:
return 4
case .Minute:
return 5
case .Second:
return 6
}
}
}
还需要覆盖相等运算符:
/// Override equality operator so Components Enum conforms to Hashable
public func == (lhs: Components, rhs: Components) -> Bool {
return lhs.toInt() == rhs.toInt()
}
答案 2 :(得分:2)
为了更具可读性,让我们用Swift 3重新实现StationSelector
:
enum StationSelector {
case nearest, lastShown, list, specific(Int)
}
extension StationSelector: RawRepresentable {
typealias RawValue = Int
init?(rawValue: RawValue) {
switch rawValue {
case -1: self = .nearest
case -2: self = .lastShown
case -3: self = .list
case (let value) where value >= 0: self = .specific(value)
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .nearest: return -1
case .lastShown: return -2
case .list: return -3
case .specific(let value) where value >= 0: return value
default: fatalError("StationSelector is not valid")
}
}
}
Apple开发人员API参考说明了Hashable
协议:
定义没有关联值的枚举时,它会自动获得
Hashable
一致性,并且您可以通过添加单个Hashable
属性将hashValue
一致性添加到其他自定义类型。
因此,由于StationSelector
实现了关联值,因此您必须手动使StationSelector
符合Hashable
协议。
第一步是实施==
运算符,并使StationSelector
符合Equatable
协议:
extension StationSelector: Equatable {
static func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
用法:的
let nearest = StationSelector.nearest
let lastShown = StationSelector.lastShown
let specific0 = StationSelector.specific(0)
// Requires == operator
print(nearest == lastShown) // prints false
print(nearest == specific0) // prints false
// Requires Equatable protocol conformance
let array = [nearest, lastShown, specific0]
print(array.contains(nearest)) // prints true
实施Equatable
协议后,您可以StationSelector
符合Hashable
协议:
extension StationSelector: Hashable {
var hashValue: Int {
return self.rawValue.hashValue
}
}
用法:的
// Requires Hashable protocol conformance
let dictionnary = [StationSelector.nearest: 5, StationSelector.lastShown: 10]
以下代码显示StationSelector
使用Swift 3使其符合Hashable
协议所需的实现:
enum StationSelector: RawRepresentable, Hashable {
case nearest, lastShown, list, specific(Int)
typealias RawValue = Int
init?(rawValue: RawValue) {
switch rawValue {
case -1: self = .nearest
case -2: self = .lastShown
case -3: self = .list
case (let value) where value >= 0: self = .specific(value)
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .nearest: return -1
case .lastShown: return -2
case .list: return -3
case .specific(let value) where value >= 0: return value
default: fatalError("StationSelector is not valid")
}
}
static func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.rawValue == rhs.rawValue
}
var hashValue: Int {
return self.rawValue.hashValue
}
}
答案 3 :(得分:1)
只是为了强调Cezar之前所说的话。如果你可以避免使用成员变量,你不需要实现equals运算符来使枚举可以使用 - 只需给它们一个类型!
enum StationSelector : Int {
case Nearest = 1, LastShown, List, Specific
// automatically assigned to 1, 2, 3, 4
}
这就是你所需要的一切。现在,您也可以使用rawValue启动它们或稍后检索它。
let a: StationSelector? = StationSelector(rawValue: 2) // LastShown
let b: StationSelector = .LastShown
if(a == b)
{
print("Selectors are equal with value \(a?.rawValue)")
}
有关详细信息,请check the documentation。