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

查看:156
本文介绍了为什么对象表达式中的代码可以从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.

因此,当您执行此操作时:

So when you do this:

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.

信用信息转到行动中的科特琳手册,其中包含该书的基础知识信息以及此处使用的示例.

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

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

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