关于Kotlin的一些基本问题

Some basic questions about Kotlin

我正在尝试学习 Kotlin 和 TornadoFX,我在 this repository

工作

目前的想法是该应用程序将显示三行,每行 7 个按钮。每个按钮代表一个已知或未知的字母。如果字母已知,它会显示在按钮上。如果字母未知,则按钮显示索引 (0-20)。

我通过创建(使用 Java 认为我确定)一个包含 21 个元素的全局数组来做到这一点。每个元素开始时都是空的。我在主应用程序中使用伴随结构定义了它:

class InteractiveClientApp : App(MainView::class) {
    companion object {
        var knownLetters = arrayOfNulls<String>(21)
    }

然后在 App 构造函数中,我用值初始化了一些随机元素,只是为了看看这是否可行(它不可行)。

override fun init() {
    knownLetters[4] = "T"
    knownLetters[9] = "G"
    knownLetters[17] = "Z"
}

然后在 LettersGridView 中,我在 knownLetters 数组上使用 forEachIndexed,这样我就可以访问数组中的元素及其索引。

import jcn.deduce.client.InteractiveClientApp.Companion.knownLetters


class LettersGridView : View() {
    override val root = gridpane {

            knownLetters.forEachIndexed { index, element ->

                if (index == 0 || index % 7 == 0) {
                    row {
                        button(element?.toString() ?: index.toString()) {
                            useMaxWidth = true
                            gridpaneConstraints {
                                marginBottom = 10.0
                            }
                        }
                    }
                } else {
                    button(element?.toString() ?: index.toString()) {
                        useMaxWidth = true
                        gridpaneConstraints {
                            marginBottom = 10.0
                        }
                    }
                }
            }
        }
    }

实际发生的是出现了三个按钮,而不是预期的 21 个,并且按钮上的值始终是索引,而不是字母值。此外,显示的索引是 20、7 和 14。不是我在设置数组中的元素时使用的三个。所以我在那里遗漏了一些东西。

另外我想我没有正确理解这一点:

 button(element?.toString() ?: index.toString()) {
                        useMaxWidth = true
                        gridpaneConstraints {
                            marginBottom = 10.0
                        }
                    }

我想说的是“如果元素值不为空,则使用元素值,否则使用索引的字符串值。这是行不通的,因为按钮上只有索引,从不字母。

我注意到如果我在元素上不使用 .toString(),我会收到一个错误,提示按钮需要字符串,而不是字符串?。这似乎有点类似于 Java 和 String vs Optional < String >。但是,当我添加 toString() 时,我收到一个 IDE 警告,指出 toString() 是多余的。

如果我去掉尾随?总的来说,我得到了一个干净的编译,但仍然只有三个按钮呈现,并且它们的标签是索引,而不是元素。

所以我很确定我在某个地方迷路了,谁能解释为什么我的程序不工作?

此外,当我调试应用程序时,我总是以两个进程结束。我不明白为什么,但这就是 IntelliJ 的样子:

这正常吗?

您的初始化函数正在运行,您可以通过将条目 20、7 或 14 的初始化更改为一个字母来确认这一点,您应该会在接下来 运行 它时看到一个字母出现。

至于您的主要问题,您看到 20、7 和 14 的原因是因为在本节中:

if (index == 0 || index % 7 == 0) {
    row {
        button(element?.toString() ?: index.toString()) {
            useMaxWidth = true
            gridpaneConstraints {
                marginBottom = 10.0
            }
        }
    }
}

您正在添加带有单个按钮的行,这些按钮将是 0、7 和 14(因为它们都是 == 0 % 7)。这意味着您只会添加三行,每行都有一个按钮。您可能对为什么它说的是 20 而不是 0 感到困惑...嗯,这是因为下一节:

else {
    button(element?.toString() ?: index.toString()) {
        useMaxWidth = true
        gridpaneConstraints {
            marginBottom = 10.0
        }
    }
}

也在添加按钮,但不添加到任何行(注意这些按钮不在行 { } lambda 内)。这意味着所有这些按钮都将被添加到彼此顶部的网格窗格中,包括第一个 0 按钮。要添加的最后一个按钮是 20,因此为什么你看到 20,它覆盖了 0!

下面是一个如何解决这个问题的例子:

val rowSize = 7
val rows = knownLetters.toList().chunked(rowSize)
rows.forEachIndexed { rowIndex, elements ->
    row {
        elements.forEachIndexed { buttonIndex, element ->
            val displayIndex = rowSize * rowIndex + buttonIndex
            button("${element ?: displayIndex}") {
                useMaxWidth = true
                gridpaneConstraints {
                    marginBottom = 10.0
                }
            }
        }
    }
}

这采用 Kotlin 库的 "chunked" 方法将 21 大小的数组分成三个大小为 7 的列表。然后您可以循环遍历(您必须使用这种方法拼凑显示索引)为每个列表创建一个新行(3 个列表构成 3 行),同时在行的 lambda 内的嵌套循环中创建按钮。

这里要注意的关键是,并不是所有的按钮都被添加到一行 { } lambda 中。

至于双进程问题,如果我运行应用程序使用像这样的主要方法,我就没有这个问题:

fun main(args: Array<String>) {
    launch<InteractiveClientApp>(args)
}

希望对您有所帮助!