LoginSignup
33
31

More than 5 years have passed since last update.

SwiftのassociatedtypeをSelfに束縛する

Last updated at Posted at 2016-03-23

※ここで紹介するWorkaroundはSwift3.1で使えなくなりました。

セグフォでコンパイル出来ない状況です。
https://bugs.swift.org/browse/SR-4434
↑これと混同していました。
コンパイルは通りますが、親クラスに束縛されてしまって目的は達成できません。

 以下本文

Swift2.2になって、Protocol周りのバグが幾つか修正されて、ProtocolとClassを組み合わせて使うシチュエーションが現実的になってきました。
ということで、Swift2.2から可能になったテクニックを備忘録も兼ねて紹介します。

本題

さて、Swift2.1から、Classにおいて、返り値と引数の型としてSelfを使うことが出来るようになったのですが、associatedtypeをSelfで束縛することは、Swift2.2ではまだ出来ないように見えます。

protocol A {
    associatedtype X
}

class B: A {
    typealias X = Self // 'Self' is only available in a protocol or as the result of a method in a class; did you mean 'B'?

    @noreturn
    static func defaultInstance() -> Self { // いける
        fatalError()
    }
}

いや、XをSelfで束縛したいんですよ…
こういう時は、protocol extensionを使うことでSelfで束縛しなおすことが出来ます。

class B: A {
    typealias X = B
}

extension A where Self: B {
    typealias X = Self
}

class C: B {
}
C.X.self // C.Type

実はこのテクニック、Swift2.1ではクラスに束縛されたassociatedtypeがコンパイラに認識されなくなるバグがあったため使えませんでした。

// 以下Swift2.1
extension A where Self: B {
    typealias X = Self
}

B.X.self //'X' is ambiguous for type lookup in this context
// ↑????!?!?!?!?wwww

Swiftのアップデートで出来ることが増えました。幸せですね。
このテクニックは拙作のライブラリで使用しています。
https://github.com/tarunon/Barrel

追記(2016/03/24)

以下の方法で型を破壊することが出来ました。

protocol A {
    associatedtype X
}

extension A where Self: AnyObject {
    typealias X = Self
}

protocol B: A {
    associatedtype Y: A
    associatedtype X = Y.X // Ambiguous type name 'X' in 'Self.Y'
}

typealias, associatedtypeにおける宣言のみ再現します。
これについては、extensionによる束縛を、別のライブラリに退避させるworkaroundが有効です。

33
31
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
31