ぜのぜ

しりとりしようぜのぜのぜのぜ

Swift Generics わからん

今日でGenericsの章が終わった.なかなかややこしかったのでまとめてみる.

タイプパラメータ

まず,Swiftのタイプパラメータ*1は3種類ある.

それぞれこんな感じ.

func genericFuncion<T, U>(_ t: T, u: U) {}

struct GenericType<T, U> {}

protocol Prot {
    associatedtype T
    associatedtype U
}

generic functionっぽいことは関数様のものにも使えるのでジェネリックsubscriptとかinitを作れる.

制約

タイプパラメータには制約をつけることができてこっちは2種類ある.

それぞれこんな感じ. T: SequenceがType Constraintでwhere ....がGeneric where Clause.

func genericFuncion<T: Sequence, U>(_ t: T, u: U) where U: AnyObject, T.Element == U {}

struct GenericType<T: Sequence, U> where U: AnyObject, T.Element == U {}

protocol Prot {
    associatedtype T: Sequence
    associatedtype U: AnyObject where T.Element == U
}

文法上問題はないが,Generic Where Clausesに以下のように書いてあるのでジェネリックほげほげの制約に使うのは良くないのか?と思うけどGeneric Where Clausesを使わないと表せない制約もあるのでよくわからん.

Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function, subscript, or type.

It can also be useful to define requirements for associated types. You do this by defining a generic where clause. [https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID192

Extensions with a Generic Where Clause

Generic Where Clauseはextensionのときにも使うことができる.これを使うとある条件のときだけメソッドを定義するということができる.

extension GenericType where T.Element == Some {
    func printSome() {
        print("T is Some")
    }
}

extension GenericType where T.Element == Another {
    func printAnother() {
        print("T is Another")
    }
}

class Some {}
class Another {}
GenericType<[Some], Some>().printSome() // T is Some
// GenericType<[Another], Another>().printSome() // Referencing instance method 'printSome()' on 'GenericType' requires the types 'Another' and 'Some' be equivalent

加えてこれをメソッドごとに書くこともできる.

extension GenericType {
    func printSome() where T.Element == Some {
        print("T is Some")
    }

    func printAnother() where T.Element == Another {
        print("T is Another")
    }
}

class Some {}
class Another {}
GenericType<[Some], Some>().printSome() // T is Some
// GenericType<[Another], Another>().printSome() // Referencing instance method 'printSome()' on 'GenericType' requires the types 'Another' and 'Some' be equivalent

*1:これは一般的な呼称?