Kotlin覚書 - 複数の総称型の場合と、上限制約 @Generics

# KotlinでGenerics
自分の無知さを痛感して、改めてDialogFragmentについて実装しているときに、以下のコード展開されている投稿を発見しました。
https://qiita.com/kojionilk/items/9584c012679f61569995

staticなBuilderクラスをMyDialogFragmentに実装して、ActivityやFragmentからの場合はthisを渡すだけで簡単にダイアログ表示できるようなものです。

これはいい！でもJavaで書かれてる！！！

ということで、Kotlin化してみようと思ったら、案の定つまづきました。

## 引数の総称型が違うコンストラクタ

```:java
public class Test {
    private AppCompatActivity fieldActivity;
    private Fragment fieldFragment;

    public <A extends AppCompatActivity & DialogActionInterface> Test(final A activity) {
        fieldActivity = activity;
    }

    public <F extends Fragment & DialogActionInterface> Test(final F fragment) {
        fieldFragment = fragment;
    }
}
```

コンストラクタの引数に対しての総称型が違うパターンです。

ちょっとわからないので、必殺Java→Kotlinへのコンバートをしてみました。

```:kotlin
class Test {
    private val fieldActivity: AppCompatActivity
    private val fieldFragment: Fragment

    constructor(activity: A) { // GenericsのAの型指定がないためエラーになってる
        fieldActivity = activity
    }

    constructor(fragment: F) {　// GenericsのFの型指定がないためエラーになってる
        fieldFragment = fragment
    }
}
```

### 結果→失敗
うまくいかないようです。Genericsの型指定がコンバートするとどこかにいってしまいました。
こりゃこまった。

やはりここはリファレンスを読もうということで、読みました。
https://kotlinlang.org/docs/reference/generics.html

総称型については、classで指定してあげればいいようです。

## Kotlinでの方法
```:kotlin
class Test<A:AppCompatActivity, F:Fragment> {
    private var fieldActivity: AppCompatActivity?
    private var fieldFragment: Fragment?

    constructor(activity: A) {
        fieldActivity = activity
    }

    constructor(fragment: F) {
        fieldFragment = fragment
    }
}
```

元のクラスで指定してあげればいいのでした。

Genericsの場合は使用方法も他に書いてあったので、場合によってうまく使い分けられそうです。
参考：https://qiita.com/k5n/items/18adb5c3503a54e96c22

inやoutなどの使い方があり、総称型の定義をする前につけてあげればいいようです。

```:kotlin
class Test<in A: AppCompatActivity, in F:Fragment> {
    private var fieldActivity: AppCompatActivity?
    private var fieldFragment: Fragment?

    constructor(activity: A) {
        fieldActivity = activity
    }

    constructor(fragment: F) {
        fieldFragment = fragment
    }
}
```

↑だと、引数としてのみの使用であればinをつけます。
逆に、戻り値としてのみ使用する場合はoutをつけます。

さて、これで総称型AとFについて、型の指定ができました。
が、まだ元のJavaコードとは差異があります。

## 上限制約
一番上のJavaコードをもう一度みてみましょう。

```:java
public class Test {
    private AppCompatActivity fieldActivity;
    private Fragment fieldFragment;

    public <A extends AppCompatActivity & DialogActionInterface> Test(final A activity) {
        fieldActivity = activity;
    }

    public <F extends Fragment & DialogActionInterface> Test(final F fragment) {
        fieldFragment = fragment;
    }
}
```

2つのコンストラクタで渡す引数がそれぞれ違うのと、さらに総称型に指定している型が複数です。

こういうときの扱いをよくわかってないため、@ngsw_taroさんの
http://kotlin.hatenablog.jp/entry/2012/12/17/234300
こちらの記事を参考に勉強させてもらいました。

こういう上限制約の場合、kotlinでは**where** を使います。

whereで上限制約をして、総称型の指定を複数にします。

```:kotlin
class Test<A, F> where A:AppCompatActivity?, A:DialogActionInterface?, F:Fragment?, F:DialogActionInterface? {
    private var fieldActivity: AppCompatActivity?
    private var fieldFragment: Fragment?

    constructor(activity: A) {
        fieldActivity = activity
        fieldFragment = null
    }

    constructor(fragment: F) {
        fieldFragment = fragment
        fieldActivity = null
    }
}
```

とりあえず、これで構文的なエラーは解消されました。

Genericsについてはまだまだ使い方に慣れてませんが、もう少し勉強が必要です。

何かツッコミあればご意見くださいm(_ _)m