【问题标题】:How about "this" as a type? [closed]“this”作为一种类型怎么样? [关闭]
【发布时间】:2022-01-09 23:34:03
【问题描述】:

我会简化让我走到这一步的问题,但我正在考虑这段代码:

abstract class A {
    fun myCustomApply(block: A.() -> Unit): A {
        this.block()  // block() would have the same effect
        // Do something else here
        return this
    }
}

class B : A() {
    fun anotherFunction() {
        // Do something
    }
}

这段代码看起来(并且)没问题。但请考虑以下 sn-p :

fun doSomethingVeryUseful(): B /* Won't work */ {
    val b = B()
    return b.myCustomApply {
        anotherFunction()  // Nope
    }
}

在这里,编译器会抱怨,原因有两个,乍一看可能并不明显。首先myCustomApplyblock参数是用A.() -> Unit类型声明的,所以我们不能在其作用域内调用anotherFunction(),因为它是在B类中声明的。 然后,doSomethingVeryUseful 的返回类型似乎被声明为 B,但 myCustomApply 返回 A,所以我们必须使用 as A 强制转换。

这两个错误都是合乎逻辑的,因为编译器无法自行猜测“哦,是的,返回类型是 A,但它总是返回 this,所以这样做完全没问题!”,但这些有点痛苦正确处理,因为我个人想不出合适的解决方法。

当然,你可以这样做:

abstract class A

class B : A() {
    fun anotherFunction() {
        // Do something
    }
}

fun <T : A> T.myCustomApply(block: T.() -> Unit): T {
    this.block()
    // Do something else
    return this
}

但我个人认为这不是一个好主意,因为它混淆了代码(myCustomApply 来自哪里?为什么不在 A 类中?),并且对于这样一个简单的问题有点复杂。你可以认为这是一个很好的解决方案,但我并不同意。

我的想法是做这样的事情(不要在你的 IDE 中尝试这个,它只会抱怨你是有史以来最糟糕的开发者,你甚至不应该存在,因为它不是实际的语法) :

abstract class A {
    fun myCustomApply(block: this.() -> Unit): this {
        block()
        // Do something else
        return this
    }
}

class B : A() {
    fun anotherFunction() {
        // Do something
    }
}

fun doSomethingVeryUseful(): B {
    val b = B()
    return b.myCustomApply {
        anotherFunction()  // YEAH
    }
}

请注意,this 用于两个地方:作为接收器类型和返回类型。 由于this 已经是关键字,它不会破坏任何现有代码,因此保证了向后兼容性。

this 作为一个类型将有一个可接受的值,即this。为什么使用this 作为类型?这将向编译器保证该值实际上是接收器的类型,即 b.myCustomApply 现在接受 B.() -&gt; Unit 类型的 lambda,并具有 B 类型的返回类型,因为 b 本身是类型B.

另一个(纯粹的美学)优势是,现在很清楚同一个对象(即接收者)将被传递给 lambda,然后返回给方法的调用者。

这将转化为这样的东西:


abstract class A<_this : A<_this>> {
    private fun _this(): _this =
         @Suppress("UNCHECKED_CAST") (this as _this)        
    
    fun myCustomApply(block: _this.() -> Unit): _this {
        _this().block()
        // You got the idea
        return _this()
    }
}

class B : A<B>() {
    fun anotherFunction() {
        // Do something
    }
}

_this 类型参数的名称很容易解释它的作用,如果 A 已经有类型参数,那么应该在它们的开头添加 _this,以及任何形式为 A 应扩展为 A

this 作为返回类型将要求 return thisreturn /* something that has this as type */ 是唯一允许的 return 语句,因为我们无法确保任何其他值实际上总是与 @987654348 具有相同类型@。

我建议this(多么棒的双关语啊),因为我有好几次觉得需要这样一个功能,但我不确定这是否是个好主意,如果可行的话,以及是否真的有人感兴趣。

无论哪种情况,感谢您的阅读,祝您有美好的一天!

【问题讨论】:

  • 嗨 - 你是在寻求帮助来解决问题吗?我不清楚你想要达到什么目标。看来您有一个解决方法(尽管我认为可以使用泛型对其进行改进)。但是首先你能阅读关于如何提问的 StackOverflow 指南,然后更新你的帖子吗?如果你想提出一个新的 Kotlin 功能,你在 JetBrains YouTrack 上搜索过吗?最后,接收器的改进即将到来,您可能感兴趣:youtrack.jetbrains.com/issue/KT-42435
  • SO 是一个问答网站。您不是在问问题,而是在提出语言功能。 Kotlin 开源项目和/或 slack 组将是一个更好的地方。
  • 啊,所以现在您编辑了问题以添加“我的”答案,所以我的答案看起来很傻。太好了。
  • 感谢您的回答(这不是真正的答案,因为我的问题不是真正的问题)。我看到这已经被要求了(这并不让我感到惊讶),所以我不会在 ASemy 发送的链接中询问它(但谢谢!)。我忘记了 Stackoverflow 只是来问问题的,所以我会压制它,因为它是一个提议(我只是想知道你对此的看法)!
  • 我投票结束这个问题,因为这不是一个问题,并且更适合 Kotlin 论坛

标签: kotlin language-features


【解决方案1】:

关于线程 "Self Types",来自 Andrey Breslav,lead language designer for Kotlin,于 2014 年 12 月:

不幸的是,当涉及到类型系统设计时,self 类型被证明是一个挑战。我们目前看不到一种明智的实施方式

另见:

【讨论】:

    【解决方案2】:

    它并没有真正回答你的问题(假设有任何问题),但请注意你可以这样做:

    abstract class A<T : A<T>> {
        fun myCustomApply(block: T.() -> Unit): T {
            (this as T).block()  // block() would have the same effect
            // Do something else here
            return this
        }
    }
    
    class B : A<B>() { ... }
    

    【讨论】:

    • 是的,我编辑我的答案是为了添加这个底层实现而不是原来的实现(这很麻烦),因为我有同样的想法。我不太喜欢这种实现,因为这会增加代码复杂性(在 this as T 表达式之前可能需要一个 @Suppress("UNCHECKED_CAST") 以避免编译器警告,并且还应该使用 return (@Suppress("UNCHECKED_CAST") (this as T)))并且结果是当代码变大时很难阅读。但是感谢这个提议!
    猜你喜欢
    • 1970-01-01
    • 2011-02-02
    • 2011-07-02
    • 2014-06-20
    • 2018-06-23
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多