web-dev-qa-db-ja.com

Kotlin関数パラメーター:Valは再割り当てできません

コトリンで赤黒木を書きました。 FuninsertFixupは、新しい要素を挿入した後にバランスを復元します(z:Node?は新しい要素です)。ツリーバランシングのアルゴリズムは、 here (ページ2〜3)から取得されます。 問題は、Kotlinが再割り当てを許可しないことですztoz.parentandz.parent.parentzpointerにする問題は、コトリンに私が彼に何を望んでいるかをどうやって理解させるかです。

class Node(key: Int) {...}

class BinarySearchTree {
    var root: Node? = null

    fun insert(newNode: Node) {...}

    fun RotateLeft(x: Node?) {...}

    fun RotateRight(x: Node?) {...}

    fun insertFixup(z: Node?) {
        var y: Node?
        while (z?.parent?.color == "RED") {
            if (z?.parent == z?.parent?.parent?.left) {
                y = z?.parent?.parent?.right
                if (y?.color == "RED") {
                    z?.parent?.color = "BLACK"
                    y?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    z = z?.parent?.parent
                }
                if (z == z?.parent?.right) {
                    z = z?.parent
                    RotateLeft(z)
                    z?.parent?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    RotateRight(z?.parent?.parent)
                }
            } else {
                y = z?.parent?.parent?.left
                if (y?.color == "RED") {
                    z?.parent?.color = "BLACK"
                    y?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    z = z?.parent?.parent
                }
                if (z != z?.parent?.left) {
                    z = z?.parent
                    RotateLeft(z)
                    z?.parent?.color = "BLACK"
                    z?.parent?.parent?.color = "RED"
                    RotateRight(z?.parent?.parent)
                }
            }
        }
        root?.color = "BLACK"
    }
}

fun main(args: Array<String>) {
    val bst = BinarySearchTree()

    while (true) {
        var newNode = Node(readLine()!!.toInt())
        bst.insert(newNode)
        bst.insertFixup(newNode)
    }
}

UPD:どうもありがとう!すべての答えは有用であり、私はあなたの返信で解決策を見つけました。

10

Kotlinの関数パラメーターは関数内では読み取り専用valであるため、ここでzは常に渡された元のオブジェクトを参照します。

関数の実行中にポイントするものを変更する必要がある場合は、関数の先頭でローカルコピーを作成する必要があります。その後、varを作成できます。

たとえば、次のように関数を開始できます。

fun insertFixup(_z: Node?) {
    var z = _z
15
zsmb13

Kotlin関数パラメーターは読み取り専用の値であり、割り当てできません。

ただし、ReadWritePropertyを取得/設定するためにinsertFixupに渡す newNode オブジェクトを作成できます。

...
class BinarySearchTree {
...
    fun insertFixup(zProperty: ReadWriteProperty<Any?, Node?>) {
        var z by zProperty
...

fun main(args: Array<String>) {
    val bst = BinarySearchTree()

    var newNode: Node? = null
    val newNodeProperty = object : ReadWriteProperty<Any?, Node?> {
        override operator fun getValue(thisRef: Any?, property: KProperty<*>): Node? {
            return newNode
        }

        override operator fun setValue(thisRef: Any?, property: KProperty<*>,
                                       value: Node?) {
            newNode = value
        }
    }

    while (true) {
        newNode = Node(readLine()!!.toInt())
        bst.insert(newNode!!)
        bst.insertFixup(newNodeProperty)
    }
}

変数の代わりにプロパティを使用する場合は、代わりにnewNodeからinsertFixupを取得/設定するために プロパティ参照 を使用できます。

...
class BinarySearchTree {
...
    fun insertFixup(zProperty: KMutableProperty0<Node?>) {
        var z by zProperty
...

var newNode: Node? = null

fun main(args: Array<String>) {
    val bst = BinarySearchTree()

    while (true) {
        newNode = Node(readLine()!!.toInt())
        bst.insert(newNode!!)
        bst.insertFixup(::newNode)
    }
}

// the following allow `KMutableProperty0` to be used as a read/write delegate
operator fun <T> KProperty0<T>.getValue(thisRef: Any?, property: KProperty<*>): T = get()
operator fun <T> KMutableProperty0<T>.setValue(thisRef: Any?, property: KProperty<*>, 
                                               value: T) = set(value)
5
mfulton26

私もこの問題に遭遇しました。私がやったことは、データクラスを作成し、そのデータクラスをパラメーターとして渡し、そのパラメーターを使用してそのプロパティを変更することでした。

data class SomeDataClass(
    val x: Int,
    val y: Int,
    val z: Int
)

fun someMethod(someDataClass: SomeDataClass) {
    someDataClass.z = 23 //whatever Int value you please
    // more computations...
    someDataClass.z = 67 // or whatever new value you need to assign.
}

fun parentMethod() {
    val someDataClass = SomeDataClass()
    someMethod(someDataClass)
    val newZValue = someDataClass.z // someDataClass holds modified data from above 
                                    // method
}
0
Bryan Neuberger