48620


とくに意味をなさないうえに冗長なコードですが、サンプルのために、下記のようなソースがあるとします。

[code]

    class Hoge<T: Equatable, U: Equatable> {
        var x: T?
        var y: U?
    
        init() {
        }
    }
    
    typealias TT = String
    typealias UU = Int
    
    let hoge = Hoge<TT, UU>()
    
[/code]

`T`には`String`。 `U`には`Int`を教えることができました(この`教える`にあたる専門用語を忘れてしまいました...
追記：`特殊化(specialization)`でした)。

これと同じことをするファクトリーのような関数を作りたいと考え下記のようにしましたがうまくいきません。うまい書き方はありますか？

[code]

    func hogeFactory<TT: Equatable, UU: Equatable>() -> Hoge<TT, UU> {
        return Hoge<TT, UU>()
    }
    
    let h = hogeFactory<String, Int>()
    
[/code]

> MyPlayground.playground:12:20: note: while parsing this '<' as a type
> parameter bracket  
>  let h = hogeFactory()


CC BY-SA 4.0
2018-09-21T08:21:04.160
48617
2019-06-29T08:52:01.770
2019-06-29T08:52:01.770
9008
9008
question
swift ジェネリクス
ジェネリクスに型を教えた状態のクラスを返したい


コメントに書きましたが、Swiftではジェネリック関数を呼び出す時、ジェネリックパラメータ(この例でいう`TT`や`UU`に当てはめるための具体的な型)を明示的に指定することはできません。

[code]

    func hogeFactory<TT: Equatable, UU: Equatable>() -> Hoge<TT, UU> {
        return Hoge<TT, UU>()
    }
    
    let h = hogeFactory<String, Int>() //<-これはエラーになる
    
[/code]

もちろん型が決定できないのでは、別のエラーになります。では、どうやって指定するのかというと、型推論でそれが決定できるようにしてやらないといけません。

例えばこんな感じ。

[code]

    let h: Hoge<String, Int> = hogeFactory()
    
[/code]

ただ、これではせっかくファクトリーメソッドを作って、表から`Hoge`クラスの存在を隠したのに、あまり意味がない(普通にイニシャライザを使った方が簡単…)ように見えるので、こんな書き方もよくします。

[code]

    func hogeFactory<TT: Equatable, UU: Equatable>(_:TT.Type, _:UU.Type) -> Hoge<TT, UU> {
        return Hoge<TT, UU>()
    }
    
    let hh = hogeFactory(String.self, Int.self)
    
[/code]

後者の書き方(型推論ができるようにするためだけの型引数を持たせる)と言うのは、Swiftの標準ライブラリでもよく使われているのですが、何か動的に型が指定できるような気がしてくるという欠点があります。(Swiftの型推論はコンパイル時に働く、実行時に動的に働くのではない。)

その辺はまた実際の問題に遭遇した時に再度質問してもらった方がいいでしょう。


CC BY-SA 4.0
2018-09-21T08:59:24.333
48620
2018-09-21T08:59:24.333
13972
48617
answer