Kotlin 函数参数:Val 不能重新赋值

Posted

技术标签:

【中文标题】Kotlin 函数参数:Val 不能重新赋值【英文标题】:Kotlin function parameter: Val cannot be reassigned 【发布时间】:2017-07-21 06:29:46 【问题描述】:

我在 Kotlin 中编写了红黑树。 Fun insertFixup 在插入新元素后恢复平衡(z: Node? 是新元素)。树平衡算法取自here(第2-3页)。 问题是 Kotlin 不允许我重新分配 zz.parentz。父.父。我希望 z 成为 指针。问题是如何让 Kotlin 明白我想从他那里得到什么?

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:谢谢大家!所有答案都很有帮助,我在您的回复中找到了解决方案。

【问题讨论】:

一个小提示:我认为如果您检查z 是否为null 或者不只在insertFixup 的开头检查一次,您可以大大改进代码。现在到处都有太多? ;) 在Java中,可以通过在参数前添加final关键字将函数参数设为只读。好吧,Kotlin 默认有这个 【参考方案1】:

Kotlin中的函数参数基本上是只读的val在函数内部,所以这里的z会一直引用原来传入的对象。

如果您需要在函数运行时修改它所指向的内容,则必须在函数开始时制作它的本地副本,然后您可以将其设为 var

例如,您可以像这样启动您的函数,这样您就可以稍后重新分配这个本地 var

fun insertFixup(_z: Node?) 
    var z = _z
    // ...
    z = z.parent
    // ...

【讨论】:

这并没有回答关于如何使z类似指针的问题。 我不明白您为什么要制作 z 的本地副本并将其设为 var。你不能重新分配给 z,即使你像你说的那样制作它的本地副本。那是行不通的。这个答案应该是错误的或请纠正我 问题是关于在函数内部重新分配函数参数的值,例如z = z.parent。这是不可能的,但如果您改用本地 var,您可以根据需要重新分配该本地 var "如果您使用本地变量,您可以根据需要重新分配该本地变量" ...所以您仍然无法将更改应用于循环?我看不出它有什么帮助。另一个伟大的 kotlin 权衡:剥夺做基础计算机科学的能力,这样更穷的工程师就不会倒下【参考方案2】:

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)
    

如果您愿意使用属性而不是变量,那么您可以使用property reference 从insertFixup 获取/设置newNode

...
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)

【讨论】:

【参考方案3】:

我也遇到了这个问题。我所做的是创建一个数据类并将数据类作为参数传递,然后我可以使用它来修改其属性。

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

【讨论】:

【参考方案4】:

在我的例子中,我正在研究管理不同应用程序数据的内容提供者。我得到了一个新的 kotlin 文件,它从 Content Provider 继承属性,如下所示:

class ProviderClass() : ContentProvider()


ContentProvider()是一个抽象类,所以我们需要实现所有的成员。

我试图将值重新分配给 sortOrder 参数,但我遇到了这些问题。 我要解决的是, //实现成员后

....
override fun query(
        uri: Uri,
        projection: Array<out String>?,
        selection: String?,
        selectionArgs: Array<out String>?,
        sortOrder: String?
    ): Cursor? 
var _sortOrder = sortOrder
if (sortOrder == null || sortOrder == "")
            _sortOrder = NAME
        
val cursor = qb.query(db, projection, selection, selectionArgs, null, null, _sortOrder) //_sorOrder newly created variable

我创建了一个名为 _sortOrder 的新变量,并将新创建的变量放在查询方法中,在第二个为两个空值之后,我创建了一个名为 cursor 的新变量,并将我们新创建的变量设置为我们想要设置的值它。

【讨论】:

以上是关于Kotlin 函数参数:Val 不能重新赋值的主要内容,如果未能解决你的问题,请参考以下文章

scala 入门

Kotlin初级- - - 空安全.md

Kotlin初级- - - 空安全.md

什么是形参和实参?参数传递的方式都有哪些?

形参和实参

调用函数时为啥形参的值不能传给实参