Skip to content

Instantly share code, notes, and snippets.

@tarunon
Last active September 28, 2017 23:19
Show Gist options
  • Save tarunon/4d0f33a6d2525ee94b6a3ce95c7b637b to your computer and use it in GitHub Desktop.
Save tarunon/4d0f33a6d2525ee94b6a3ce95c7b637b to your computer and use it in GitHub Desktop.
// 多変数の型パラ持ちのprotocolでtype-erasureを書く時に、共変性をサポートしたいが
// 素直なtype-erasureでは引数にバラバラにpropertyを渡すことでしか共変な型消しをinitできなかった。
class Animal {}
class Cat: Animal {}
protocol A {
associatedtype X
var x: X { get }
var int: Int { get }
var string: String { get }
}
struct CatA: A {
typealias X = Cat
var x: Cat
var int: Int
var string: String
}
struct AnyA<X>: A {
var x: X
var int: Int
var string: String
}
extension AnyA {
init<O: A>(_ a: O) where O.X == X {
self.init(x: a.x, int: a.int, string: a.string)
}
}
var catA = CatA(x: Cat(), int: 1, string: "1")
//var animalA: AnyA<Animal> = AnyA(catA) // できない
var animalA: AnyA<Animal> = AnyA(x: catA.x, int: catA.int, string: catA.string) // 出来るけど面倒
// Tupleでフィールドをまとめてそれを受け取るinitを追加
extension A {
var erasureConfig: (x: X, int: Int, string: String) {
return (x: x, int: int, string: string)
}
}
extension AnyA {
init(config: (x: X, int: Int, string: String)) {
self.init(x: config.x, int: config.int, string: config.string)
}
}
// var animalB: AnyA<Animal> = AnyA(config: catA.erasureConfig) // これもダメ
// Tupleを返すFunctionにする
extension A {
var erasureBuilder: () -> (x: X, int: Int, string: String) {
return { _ in self.erasureConfig }
}
}
extension AnyA {
init(builder: () -> (x: X, int: Int, string: String)) {
self.init(config: builder())
}
}
var animalB: AnyA<Animal> = AnyA(builder: catA.erasureBuilder) // やったぜ
// ↑ @autoclosureで横着するとコンパイラクラッシュ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment