53380


クラスで自分自身を返すには↓のように実装するだけです。

[code]

    open class A {
        fun chain(): A {
            return this
        }
    }
    
[/code]

このAを継承したサブクラスで上記メソッドを実行すると  
メソッドの実装どおり、Aクラスを返すことになります。

[code]

    class B: A {
    }
    
[/code]

私はイメージとして、  
B().chain() では B クラスを返したいです。  
これを実現できる方法はありますか？

【追記】  
@kunif さんの回答は限りなく正解に近いものだと思うのですが↓のような結果になりました。  
何故かBクラスのメソッド内部でしか chain メソッドが見えなくなりました。

[code]

    open class A {
        fun <T:A>T.chain(): T {
            return this
        }
    }
    
    class B: A() {
        fun test() {
            val chainメソッド参照可能返ってくるのはBクラス = chain()
        }
    }
    
    A().chain()           //  これは当たり前だけどchainメソッドは参照できない
    val ss = B().chain()  //  ここでもchainメソッドは参照できない　できそうなのに。
    
[/code]


CC BY-SA 4.0
2019-03-12T04:01:33.237
53376
2023-01-05T01:58:38.407
2023-01-05T01:58:38.407
10346
10346
question
kotlin
Kotlinで継承先のクラスを返したい


言語の知識は無いのですが、検索したら、おそらくこれ [How to implement a Kotlin interface that refers to
the conforming type?](https://stackoverflow.com/q/52542238/9014308)
が該当すると思われます。  
回答の以下の部分でしょう。

> あるいはもっと簡単に、あなたは書くことができます。
[code]

>     fun <T:Foo>T.getSelf(): T {
>          return this as T
>      }
>  
[/code]

>
> だからあなたはただ呼ぶことができます。
[code]

>     Bar().getSelf()
>  
[/code]

>
> Fooから拡張された全てのクラスのインスタンスを取得。

上記を適用すると、以下のように出来るのでは？

[code]

    open class A {
        fun <T:A>T.chain(): T {
            return this as T
        }
    }
    
    class B: A {
    }
    
[/code]

とすれば、以下のように呼べるのでは？ **いずれも確認はしていないので試してみてください。**

[code]

    A().chain()
    B().chain()
    
[/code]

ただし、質問者は上記を解決とした後、より応用が効く方法を発見したようです。  
Google翻訳をちょっといじった程度なので、文章が怪しいですが以下になるでしょう。

> 私は fun とは対照的に、グローバル拡張 val を使用しました。  
>
> 一般的なパターンを使用せずに実装で適合型を一般的に参照する方法の質問には答えませんでしたが、より簡単でスケーラブルな方法でより大きな問題を解決しました。
[code]

>     val <Anything>Anything.self:Anything inline get() = this
>  
[/code]

* * *

**@quesera2さんコメントを受けて追記**

関数の定義はクラスの外側で、ということなので、こんな風になるようです。

[code]

    open class A {
    }
    
    fun <T:A>T.chain(): T {
        return this
    }
    
    class B: A() {
    }
    
[/code]

正しいのかどうかは不明ですが、ここ <http://try.kotlinlang.org/> で上記に加えて、  
mainを記述して実行した結果が以下になります。

[code]

    fun main(args: Array<String>) {
        val aa = A()
        val bb = B()
        println("Hello, world!")
        println(aa.chain())
        println(A().chain())
        println("Hello, world, 2nd!")
        println(bb.chain())
        println(B().chain())
        A().chain()
        B().chain()
    }
    
[/code]

結果

[code]

    Hello, world!
    A@28a418fc
    A@5305068a
    Hello, world, 2nd!
    B@1f32e575
    B@279f2327
    
[/code]


CC BY-SA 4.0
2019-03-12T05:19:24.180
53380
2019-05-22T14:39:14.553
2019-05-22T14:39:14.553
26370
26370
53376
answer

[code]

    open class A{
        open fun chain(): A {
            return this
        }
    }
    class B: A(){
        override fun chain(): B {
            return this
        }
    }    
    fun f(a: A): Unit {
        println("type A")
    }
    fun f(b: B): Unit {
        println("type B")
    }
    fun main() {
        f(A().chain()) // => type A
        f(B().chain()) // => type B
        f((B() as A).chain()) // => type A
    }
    
[/code]

一応解決法が出たようですが、もう一つ共変戻り値といわれるやりかたを付け加えておきたいと思います。  
といっても上のようにオーバーライドして元の戻り値のサブクラスに戻り値を書き換えるだけです。  
この方法は拡張メソッドの方法と違って、それぞれ戻り値の型を変えたいクラスごとにオーバーライドする必要がありますが、戻り値ごとに違った処理が書ける分こちらでなければ駄目という場合もあるので覚えておいて損はないと思います。


CC BY-SA 4.0
2019-05-22T09:57:09.237
55165
2019-05-22T16:50:15.083
2019-05-22T16:50:15.083
33033
33033
53376
answer