35961


次のコードはコンパイルできて、実行すると"F"と表示します。

[code]

    open class MyBool
    class MyTrue : MyBool()
    class MyFalse : MyBool()
    
    fun <T> select(b: Boolean, v: T, w: T): T = if (b) v else w
    
    fun main(args: Array<String>) {
        val v: MyBool = select(false, MyTrue(), MyFalse())
        when (v) {
          is MyTrue -> println("T")
          is MyFalse -> println("F")
        }
    }
    
[/code]

このうちの`select`と同ようなメソッドで`v`の代わりに`this.v`を返すものを定義したいのですが書き方が分かりません。例えば次のように書いた時、

[code]

    class A<T>(val v: T) {
       fun select(b: Boolean, w: T): T = if (b) v else w
    }
    
[/code]

`A(MyTrue()).select(MyFalse())`を`MyBool`として扱って欲しいのですが、実際は型エラーとなります。

[code]

    Typing.kt:15:46: error: type mismatch: inferred type is MyFalse but MyTrue was expected
        val v: MyBool = A(MyTrue()).select(false,MyFalse())
                                                 ^
    
[/code]

一応`T`に`out`修飾子を付加し、メソッドの代わりにextension functionを使えば近いことは達成できます。

[code]

    class A<out T>(val v: T)
    
    fun <T> A<T>.select2(b: Boolean, w: T): T = if (b) v else w
    
    fun main(args: Array<String>) {
        val v = A(MyTrue()).select2(false,MyFalse())
        when (v) {
          is MyTrue -> println("T")
          is MyFalse -> println("F")
        }
    }
    // コンパイル可、"F"を印字
    
[/code]

`select`関数と同じことをメソッドで実現するにはどうすればよいでしょうか？それともこのような場合はextension
functionを使うのが筋なのでしょうか？


CC BY-SA 3.0
2017-06-23T14:35:09.180
35839
2017-07-25T14:16:45.717
2017-06-26T14:33:04.470
13199
13199
question
kotlin
メソッドの返り値に共通のスーパークラスの型を付けたい


このサンプルのように

[code]

    val v: MyBool = A(MyTrue()).select(false,MyFalse())
    
[/code]

としてしまうと型推論によって class A は `A<MyTrue>` となってしまうと思います。そこで、

[code]

    val v: MyBool = A<MyBool>(MyTrue()).select(false,MyFalse())
    
[/code]

とすることで想定通りの動作をするかと思います。

動作を確認したものがこちら。
<https://try.kotlinlang.org/#/UserProjects/2hdaktdk2ubim65qmc67156679/658bm9nn5ih7q59m26vt04c4gt>


CC BY-SA 3.0
2017-06-29T07:12:40.263
35961
2017-06-29T08:51:57.747
2017-06-29T08:51:57.747
7949
7949
35839
answer


`select`メソッドを定義するには型のlower
boundが必要ですが、[現在のところKotlinではサポートされていません。](https://discuss.kotlinlang.org/t/covariance-
and-generic-constraints-in-kotlin/878)代わりにextension functionを使うのが妥当です。

ちなみにScalaでは`select`を書くことが出来ます。

[code]

    sealed class MyBool
    class MyTrue extends MyBool
    class MyFalse extends MyBool
    
    class A[T](val v: T) {
      def select[U >: T](b: Boolean, w: U): U = if (b) v else w
    }
    
[/code]


CC BY-SA 3.0
2017-07-25T14:16:45.717
36667
2017-07-25T14:16:45.717
13199
35839
answer