Kotlin 中 DynamicArray 的自定义 print() 打印意外结果

Custom print() of DynamicArray in Kotlin prints unexpected result

我有一个简单的场景,我有 Kotlin class DynamicArray.kt:

class DynamicArray(size: Int) {

    private var numArray: IntArray
    private var count: Int = 0

    init {
        if (size <= 0)
            throw IllegalArgumentException("Invalid value for array size")    
        numArray = IntArray(size)
    }

    fun insert(item: Int) {
        if (numArray.size == count){

            // Create newArray with double size
            val newArray = IntArray(count * 2)

            // copy old to new
            for ((index, i) in numArray.withIndex()){
                newArray[index] = i
            }

            // assign newArray to old
            numArray = newArray

        }
        numArray[count++] = item
    }

    fun print(): String {
        val arrayAsString = StringBuilder()
        arrayAsString.append("[")
        for ((index, i) in numArray.withIndex()){
            arrayAsString.append(i)
            if (index != (count - 1)){
                arrayAsString.append(", ")
            }
        }
        arrayAsString.append("]")
        return arrayAsString.toString()
    }
}

而一个简单的 Main.kt class 只有:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)

    println(array.print())

}

当 DynamicArray 的 sizeitems 相等时上面的代码工作完美

[1, 2, 3]

但是当我们插入更多项目时初始大小例如:

fun main(args: Array<String>) {
    val array = DynamicArray(3)

    array.insert(1)
    array.insert(2)
    array.insert(3)
    array.insert(4)

    println(array.print())

}

它打印奇怪的值,如:

[1, 2, 3, 40, 0, ]

更新

如果我将打印方法更改为:

fun print(): String {
        return numArray.contentToString() // using built-in method
}

它仍然打印:

[1, 2, 3, 4, 0, 0]

无法找出导致此问题的原因。

当插入不适合的新项目时,数组的大小会加倍。这意味着内部数组的大小可能比 DynamicArray 的虚拟大小

要仅显示 添加的 元素,您应该从 0 迭代到 count,而不是迭代整个数组。

一个手动追加的例子:

fun print(): String {
    val builder = StringBuilder()
    // Iterate over *inserted* indices only
    for (i in 0 until count) {
        if (builder.isNotEmpty()) {
            builder.append(", ")
        }
        builder.append(numArray[i])
    }
    builder.insert(0, "[")
    builder.append("]")
    return builder.toString()
}

使用内置函数的替代方法:(这会创建一个中间列表)

fun print(): String {
    // get a List of added elements
    val content = numArray.take(count)
    // convert the list to a string
    return content.joinToString(prefix = "[", postfix = "]")
}

首先,让我们看看如何找出问题所在。

调试技术有很多,但目前为止最有用的一般就是简单地打印内容。为了缩小问题所在的范围,能够在每个点查看程序的 state(在本例中为 DynamicArray 的内容)真的非常有用。

您希望能够添加一行,例如:

println("Point A: $array")

…每次调用 insert() 前后。问题是它只会打印出类似的东西:

Point A: DynamicArray@63947c6b

…这是因为 DynamicArray 没有覆盖 toString()。您可以改为调用 print() 方法 — 但您不知道错误是否存在。

如果 DynamicArray 是 data class,您会自动得到一个闪亮的 toString() 实现。但是这个 class 并不真正适合作为数据 class (并且需要很多其他更改)。但是没有什么能阻止你自己写,例如:

override fun toString() = "DynamicArray(count=$count, numArray=[${numArray.joinToString()}])"

有了它,您可以添加大量调试输出。例如:

Start: DynamicArray(count=0, numArray=[0, 0, 0])
Inserted 1: DynamicArray(count=1, numArray=[1, 0, 0])
Inserted 2: DynamicArray(count=2, numArray=[1, 2, 0])
Inserted 3: DynamicArray(count=3, numArray=[1, 2, 3])
Inserted 4: DynamicArray(count=4, numArray=[1, 2, 3, 4, 0, 0])
Inserted 5: DynamicArray(count=5, numArray=[1, 2, 3, 4, 5, 0])
[1, 2, 3, 4, 50, ]

这样一来,问题出在哪里就清楚多了!您可以看到 countnumArray 都设置正确。所以问题一定出在你的print()方法上。

我不打算在这里给出最终的解决方案,因为我认为这对您自己解决剩下的问题会更有帮助;我希望这已经给了你足够的开始去做那件事。 (如果您需要提示,请考虑它打印了多少数字,以及逗号放在哪里。)

即使计数较少,您的打印方法也会遍历所有元素,因此零会附加到打印的字符串。如果索引大于 count

,对代码进行最小更改的简单解决方案是打破循环
fun print(): String {
    val arrayAsString = StringBuilder()
    arrayAsString.append("[")
    for ((index, i) in numArray.withIndex()){
        if(index>=count) break;    // NEW condition
        arrayAsString.append(i)
        if (index != (count - 1)){
            arrayAsString.append(", ")
        }
    }
    arrayAsString.append("]")
    return arrayAsString.toString()
}

这是使用 Kotlin 的内置功能

DynamicArray class 的更简单代码
class DynamicArray(size: Int) {

  private var numArray: IntArray
  private var count: Int = 0

  init {
    require(size>0) { "Invalid value for array size" }
    numArray = IntArray(size)
  }

  fun insert(item: Int) {
    if (numArray.size == count) {
      numArray = numArray.copyInto(IntArray(count * 2))
    }
    numArray[count++] = item
  }

  fun print() = numArray.take(count).joinToString(", ", "[", "]")
}