56153

[code]

    class Hoge<T: Equatable>: Equatable {
        let e: T
    
        init(e: T) {
            self.e = e
        }
    
        static func == (lhs: Hoge<T>, rhs: Hoge<T>) -> Bool {
            return lhs.e == rhs.e
        }
    }
    
    class HogeA: Hoge<Int> {}
    class HogeB: Hoge<String> {}
    
    class Foo<T: Equatable, U: Hoge<T>>: Equatable {
        var ee: U
    
        init(ee: U) {
            self.ee = ee
        }
    
        static func == (lhs: Foo<T, U>, rhs: Foo<T, U>) -> Bool {
            return lhs.ee == rhs.ee
        }
    }
    
    class FooA: Foo<Int, HogeA> {}
    class FooB: Foo<String, HogeB> {}
    
    let fooA1 = FooA(ee: HogeA(e: 1))
    let fooA2 = FooA(ee: HogeA(e: 2))
    
    let fooB1 = FooB(ee: HogeB(e: "あ"))
    let fooB2 = FooB(ee: HogeB(e: "あ"))
    
    print(fooA1 == fooA2)
    print(fooB1 == fooB2)
    
[/code]

上記のコードにおいて

[code]

    class Foo<T: Equatable, U: Hoge<T>>: Equatable {
       ...
    }
    
    class FooA: Foo<Int, HogeA> {}
    class FooB: Foo<String, HogeB> {}
    
[/code]

の部分が、特殊化の引数を2つ取って冗長です。

本当は

[code]

    class Foo<U: Hoge<T: Equatable>>: Equatable { // 文法エラー
        ...
    }
    
    class FooA: Foo<HogeA> {}
    class FooB: Foo<HogeB> {}
    
[/code]

としたいのですが、Fooの定義をうまく書けません（文法エラー）。  
なにかうまい書き方はSwiftに用意されていますか？


CC BY-SA 4.0
2019-06-27T12:39:06.210
56146
2019-06-29T08:46:33.243
2019-06-29T08:46:33.243
9008
9008
question
swift ジェネリクス
クラスのジェネリクスの特殊化の冗長な書き方をなくしたい


ではこうですかね？

[code]

    protocol HogeProtocol: Equatable {
    
        associatedtype Value
    }
    
    class Hoge<T: Equatable>: HogeProtocol {
    
        typealias Value = T
    
        let e: T
    
        init(e: T) {
            self.e = e
        }
    
        static func == (lhs: Hoge<T>, rhs: Hoge<T>) -> Bool {
            return lhs.e == rhs.e
        }
    }
    
    class Foo<T: HogeProtocol>: Equatable {
    
        var ee: T
    
        init(ee: T) {
            self.ee = ee
        }
    
        static func == (lhs: Foo<T>, rhs: Foo<T>) -> Bool {
            return lhs.ee == rhs.ee
        }
    }
    class HogeA: Hoge<Int> {}
    class HogeB: Hoge<String> {}
    
    class FooA: Foo<HogeA> {}
    class FooB: Foo<HogeB> {}
    
    
    let fooA1 = FooA(ee: HogeA(e: 1))
    let fooA2 = FooA(ee: HogeA(e: 2))
    
    let fooB1 = FooB(ee: HogeB(e: "あ"))
    let fooB2 = FooB(ee: HogeB(e: "あ"))
    
    print(fooA1 == fooA2)
    print(fooB1 == fooB2)
    
[/code]

* * *

こういうのは出来ますけど目的とは違います？

[code]

    class Hoge<T: Equatable>: Equatable {
        let e: T
    
        init(e: T) {
            self.e = e
        }
    
        static func == (lhs: Hoge<T>, rhs: Hoge<T>) -> Bool {
            return lhs.e == rhs.e
        }
    }
    
    class Foo<T: Equatable>: Equatable {
        var ee: Hoge<T>
    
        init(ee: Hoge<T>) {
            self.ee = ee
        }
    
        static func == (lhs: Foo<T>, rhs: Foo<T>) -> Bool {
            return lhs.ee == rhs.ee
        }
    }
    
    
    let fooA1 = Foo(ee: Hoge(e: 1))
    let fooA2 = Foo(ee: Hoge(e: 2))
    
    let fooB1 = Foo(ee: Hoge(e: "あ"))
    let fooB2 = Foo(ee: Hoge(e: "あ"))
    
    print(fooA1 == fooA2)
    print(fooB1 == fooB2)
    
[/code]


CC BY-SA 4.0
2019-06-27T14:41:18.800
56152
2019-06-27T15:15:11.747
2019-06-27T15:15:11.747
2741
2741
56146
answer


Swiftの場合、ジェネリッククラスを参照する場合は、必ずジェネリックパラメータを決定してやる(型推論で決定できる場合は省略できるが、そうでなければ明示)必要があるので、`Hoge<T>`のようにパラメータをジェネリックなままにしておきたいと言うときには、ご質問に掲載されたように2つジェネリックパラメータを使う書き方しかないように思います。(私が思いつかないだけかもしれませんが…。)

完全に同じ制約と言うわけにはいきませんが、プロトコルを使えば、こんな感じには書けます。

[code]

    protocol HogeProtocol: class, Equatable {
        associatedtype E: Equatable
    
        var e: E {get}
    
        init(e: E)
    
    }
    extension HogeProtocol {
        static func == (lhs: Self, rhs: Self) -> Bool {
            return lhs.e == rhs.e
        }
    }
    class Hoge<T: Equatable>: HogeProtocol {
        typealias E = T
    
        let e: T
    
        required init(e: T) {
            self.e = e
        }
    }
    
    class HogeA: Hoge<Int> {}
    class HogeB: Hoge<String> {}
    
    class Foo<U: HogeProtocol>: Equatable {
        var ee: U
    
        init(ee: U) {
            self.ee = ee
        }
    
        static func == (lhs: Foo<U>, rhs: Foo<U>) -> Bool {
            return lhs.ee == rhs.ee
        }
    }
    
    class FooA: Foo<HogeA> {}
    class FooB: Foo<HogeB> {}
    
    let fooA1 = FooA(ee: HogeA(e: 1))
    let fooA2 = FooA(ee: HogeA(e: 2))
    
    let fooB1 = FooB(ee: HogeB(e: "あ"))
    let fooB2 = FooB(ee: HogeB(e: "あ"))
    
    print(fooA1 == fooA2) //->false
    print(fooB1 == fooB2) //->true
    
[/code]

`associatedtype`付きのプロトコルを使うことにより、`HogeProtocol.E`のような情報をジェネリックパラメータ(元コードの`Foo`側の`T`)に宣言する必要がなくなります。


CC BY-SA 4.0
2019-06-27T15:06:43.683
56153
2019-06-27T15:06:43.683
13972
56146
answer