为什么对象表达式中的代码可以访问 kotlin 中包含它的范围内的变量? [英] Why the code in an object expression can access variables from the scope that contains it in kotlin?

查看:11
本文介绍了为什么对象表达式中的代码可以访问 kotlin 中包含它的范围内的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Kotlin 中,对象表达式中的代码可以访问包含它的作用域中的变量,就像下面的代码:

In Kotlin,the code in an object expression can access variables from the scope that contains it, just like the following code:

fun countClicks(window: JComponent) {
   var clickCount = 0
   var enterCount = 0
   window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        clickCount++
    }

    override fun mouseEntered(e: MouseEvent) {
        enterCount++
    }
   })
}

但是为什么呢?在 Java 中,这是不允许的,因为对象的生命周期与局部变量不同,所以当你尝试时 enterCountclickCount 可能是无效的访问对象.有人能告诉我 Kotlin 是如何做到的吗?

But why? In Java, it's not allowed to do this, because the life cycle of the object is different from the local variables, so the enterCount or clickCount maybe be invalid when you try to access the object. Can someone tell me how Kotlin does this?

推荐答案

在 Java 中,您只能(有效地)捕获匿名类和 lambda 中的最终变量.在 Kotlin 中,您可以捕获任何变量,即使它们是可变的.

In Java, you can only capture (effectively) final variables in anonymous classes and lambdas. In Kotlin, you can capture any variable, even if they are mutable.

这是通过将任何捕获的变量包装在简单包装类的实例中来完成的.这些包装器只有一个包含捕获变量的字段.由于包装器的实例可以是 final,它们可以像往常一样被捕获.

This is done by wrapping any captured variables in instances of simple wrapper classes. These wrappers just have a single field that contains the captured variables. Since the instances of the wrappers can be final, they can be captured as usual.

所以当你这样做时:

var counter = 0
{ counter++ }()   // definition and immediate invocation, very JavaScript

类似的事情发生在幕后:

Something like this happens under the hood:

class Ref<T>(var value: T) // generic wrapper class somewhere in the runtime

val counter = Ref(0);      // wraps an Int of value 0
{ counter.value++ }()      // captures counter and increments its stored value

包装类的实际实现是用Java编写的,如下所示:

The actual implementation of the wrapper class is written in Java, and looks like this:

public static final class ObjectRef<T> implements Serializable {
    public T element;

    @Override
    public String toString() {
        return String.valueOf(element);
    }
}

还有称为 ByteRefShortRef 等的附加包装器,用于包装各种原语,以便它们不必为了被捕获而装箱.您可以在 此文件.

There are also additional wrappers called ByteRef, ShortRef, etc. that wrap the various primitives so that they don't have to be boxed in order to be captured. You can find all the wrapper classes in this file.

积分转至 Kotlin in Action 一书,其中包含本教程的基础知识信息,以及此处使用的示例.

Credits go to the Kotlin in Action book which contains the basics of this information, and the example used here.

这篇关于为什么对象表达式中的代码可以访问 kotlin 中包含它的范围内的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆