しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

Swiftのassociatedtype再勉強

Swiftのassociatedtypeの仕様を再度勉強しました。

associatedtypeを使うと下のように独自の型(下の例だとMyType)を定義することができます。

protocol MyProtocol {
    associatedtype MyType
}

定義した型は下のようにメソッドの引数や戻り値に使うことができます。

protocol MyProtocol {
    associatedtype MyType
}

extension MyProtocol {
    func myMethod(myValue: MyType) -> MyType {
        return myValue
    }
}

MyTypeの型は、MyProtocolに準拠したクラスでtypealiasを使う事で定義できます。
下の例だとMyTypeをIntにしているので、myMethodの引数や戻り値はIntになっています。

class MyClass: MyProtocol {
    typealias MyType = Int
}

MyClass().myMethod(myValue: 1) // → 1

typealiasで型の定義をしない場合はコンパイルエラーになります。

class MyClass: MyProtocol { // エラーになる
}

associatedtypeの型はprotocolやclassで制限をかけることができます。

class MyAssociatedType {
}

protocol MyProtocol {
    associatedtype MyType: MyAssociatedType
}

上記制限をかけた場合、先程のようにMyTypeをIntにしようとするとエラーになります。

class MyClass1: MyProtocol { // エラー
    typealias MyType = Int
}

class MyClass2: MyProtocol { // OK
    typealias MyType = MyAssociatedType
}

class MyClass3: MyProtocol { // OK
    typealias MyType = MyAssociatedSubType
}

class MyAssociatedSubType: MyAssociatedType {
}

associatedtypeは下のようにジェネリクスを使うこともできます。

protocol MyProtocol {
    associatedtype MyType
}

class MyClass<T>: MyProtocol {
    typealias MyType = T
    
    func myMethod(value: MyType) -> MyType {
        return value
    }
}

MyClass<Int>().myMethod(value: 1) // → 1
MyClass<String>().myMethod(value: "AAA") // → "AAA"

以下のような書き方をすることでtypealiasを省略することも可能です。
MyClassのmyMethodの引数をTにすることで、MyTypeの型も決まるようになっています。

protocol MyProtocol {
    associatedtype MyType
    
    func myMethod(value: MyType) -> MyType
}

class MyClass<T>: MyProtocol {
    func myMethod(value: T) -> T {
        return value
    }
}