こちらの記事を読んで、IndexPathをIntの配列リテラルから生成したりIndexPathとInt配列の比較ができる事を知りました。
今回はなぜこのような事ができるかを調べてみました。
[iOS][Swift] IndexPathはInt配列リテラルから作れる。Int配列リテラルとの比較もできる
let indexPath: IndexPath = [0, 0] if indexPath == [1, 1] { }
Intの配列リテラルからIndexPathを生成できる理由
Intの配列リテラルからIndexPathを生成できるのは、IndexPathがExpressibleByArrayLiteralプロトコルに準拠しているからでした。
let indexPath: IndexPath = [0, 0]
ExpressibleByArrayLiteralは下のようなもので、配列リテラルをそのクラスに変更する事ができます。
public protocol ExpressibleByArrayLiteral { /// The type of the elements of an array literal. associatedtype Element /// Creates an instance initialized with the given elements. public init(arrayLiteral elements: Self.Element...) }
自作クラスをExpressibleByArrayLiteralに準拠させたらIntの配列リテラルからクラスに変換できるようになりました。
class MyClass: ExpressibleByArrayLiteral { typealias Element = Int required init(arrayLiteral elements: Int...) { print(elements) // → [1, 2, 3] } } let myValue: MyClass = [1, 2, 3]
IndexPathとInt配列の比較ができる理由
比較できるのは、IndexPathがEquatableに準拠しているからでした。
Equatableは下のようなプロトコルで、準拠するとそのクラス同士の比較ができます。
public protocol Equatable { /// Returns a Boolean value indicating whether two values are equal. /// /// Equality is the inverse of inequality. For any values `a` and `b`, /// `a == b` implies that `a != b` is `false`. /// /// - Parameters: /// - lhs: A value to compare. /// - rhs: Another value to compare. public static func ==(lhs: Self, rhs: Self) -> Bool }
下のように比較演算子を使えるようになります。
class MyClass: Equatable { static func ==(lhs: MyClass, rhs: MyClass) -> Bool { return true } } print(MyClass() == MyClass())
これを先程のExpressibleByArrayLiteralと合わせることで、「IndexPath(row: 0, section: 0) == [0, 1]はIndexPath(row: 0, section: 0) == IndexPath(row: 1, section: 0)と同じ意味」 → 「EquatableによってIndexPath同士の比較は可能」→「IndexPathとIntの配列リテラルの比較ができる」となります。
試したところ、自作クラスをInt配列リテラルと比較する事ができました。
class MyClass: ExpressibleByArrayLiteral, Equatable { typealias Element = Int required init(arrayLiteral elements: Int...) { print(elements) } static func ==(lhs: MyClass, rhs: MyClass) -> Bool { return true } } let myValue: MyClass = [1, 2, 3] print(myValue == [1, 2, 3]) switch myValue { case [1, 1]: break default: break }