「ステーション」の選択を表す列挙型を定義しました。ステーションは一意の正の整数で定義されるため、負の値が特別な選択を表すことができるように次の列挙型を作成しました。
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
に準拠する必要があり、コンパイラーを満たすために列挙型で等号演算子を定義することはできません。
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
コンパイラは、これが1行の2つの宣言であり、;
func
の後。これも意味がありません。
何かご意見は?
Swift本から:
関連付けられた値のない列挙型メンバー値(列挙型で説明されている)も、デフォルトでハッシュ可能です。
ただし、列挙には関連付けられた値を持つメンバー値があるため、Hashable
準拠を手動で追加する必要があります。
実装の問題は、Swiftの演算子宣言はグローバルスコープである必要があることです。
移動するだけです:
func == (lhs: StationSelector, rhs: StationSelector) -> Bool {
return lhs.toInt() == rhs.toInt()
}
enum
定義の外にあり、それは機能します。
詳細については、 ドキュメント を確認してください。
関連する値を持つenum
をHashable
に準拠させようと少し努力しました。
関連付けられた値がenum
に準拠するようにHashable
をソートして使用したり、Dictionary
キーとして使用したり、Hashable
ができることをすべて実行したりします。行う。
関連付けられた値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()
}
読みやすくするために、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]
以下のコードは、Swift 3を使用してStationSelector
プロトコルに準拠させるために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
}
}
前にセザールが言ったことを強調するためだけに。メンバー変数の使用を避けることができる場合は、enumをハッシュ可能にするために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)")
}
詳細については、 ドキュメントを確認してください 。