如何将变量从主函数传递到另一个函数并对其进行修改?(Kotlin)

4

我知道传递给函数的参数会被视为“val”,即使变量被初始化为“var”。但这对我来说是一个问题。在下面的示例代码中,我想通过使用函数“changeNum”来修改变量“num”的值。但当然,Kotlin不允许我修改它。我该如何解决这个问题?如何使用函数“changeNum”来修改变量“num”?

fun main() {
    var num: Int = 5
    changeNum(num)
}

fun changeNum(num: Int){
    num += 2
    print(num)
}

2
那你为什么不把你的方法changeNum改成fun changeNum(num: Int): Int,然后返回你想要的值呢? - Steve.P
2
同意@Steve.P的观点。还请查看此答案 https://dev59.com/SVcP5IYBdhLWcg3wXI3Z#54689951 - Akbolat SSS
3个回答

3

使用 Kotlin 中的属性(property)也可以实现这一点。

import kotlin.reflect.KMutableProperty0

var num = 1

fun main() {
    println(num)
    changeNum(::num)
    println(num)
}

fun changeNum(numProperty: KMutableProperty0<Int>) {
    numProperty.set(12345)
}

>> 1
>> 12345

KMutableProperty0 表示一个基本的 var,因此您可以使用::num语法(与传递函数引用的方式相同)传递属性引用。这样,您不是传递当前值,而是向函数提供属性本身的引用,然后您可以在其上调用 set

但问题是,你真的想这样做吗?或者你是在过度复杂化一些应该以更简单或更可读的方式完成的事情吗?你实际上不能在fun main()中像你试图做的那样使用一个变量,只能是对象上的属性(基本上是顶层变量) - 但即使您可以,为什么不使用下面这个方法呢?

fun main() {
    var num: Int = 5
    ...
    num = changeNum(num) // this would need renaming but y'know
}

这仍然是一行代码调用,您的changeNum函数仍然可能具有副作用,可以进行验证等操作,只是返回结果而不是设置为副作用。这样更容易理解,特别是当它是在对象上设置值的常规方式时。


如果您真的想使用引用(references),但将它们置于类中的顶层很麻烦,那么也许考虑创建一个状态对象:

import kotlin.reflect.KMutableProperty0

data class AllThemNums(var num1 :Int = 1, var num2: Int = 9999)

fun main() {
    val nums = AllThemNums(num1 = 5)
    changeNum(nums::num1)
    println(nums)
}

fun changeNum(numProperty: KMutableProperty0<Int>) {
    numProperty.set(numProperty.get() + 2)
}


>> AllThemNums(num1=7, num2=9999)

你甚至可以将changeNum函数放在数据类内部!


3

Kotlin是按值传递的,所以您不能直接对原始类型(如Int)进行此操作。

通常的方法是返回一个新值,而不是修改您作为参数接收的值(一种函数式方法)。从调用代码的角度来看,这使得代码更清晰:

fun main() {
    var num: Int = 5
    num = changeNum(num)
}

fun changeNum(num: Int): Int {
    val newValue = num + 2
    print(newValue)
    return newValue
}

如果您真的想要改变变量而不是返回新值,我考虑到两种方法来实现这一点:
1.将所有操作该值的代码放入一个类中,并将局部变量作为该类的属性(这是面向对象的方法) 2.将这个基本变量放入一个类中,并传递该类的实例
选项1的代码如下:
class SomeClass(var num: Int) {

    fun changeNum() {
        num += 2
        print(num)
    }
}

fun main() {
    val container = SomeClass(5)
    container.changeNum()
}

选项2的显示如下:

class SomeMutableContainer(var num: Int)

fun main() {
    val container = SomeMutableContainer(5)
    changeNum(container)
}

fun changeNum(container: SomeMutableContainer) {
    container.num += 2
    print(container.num)
}

你可以通过传递属性来实现:fun changeNum(num: MutableProperty<Int>) {} - Jorn
我猜MutablePropertySomeMutableContainer选项的一种特殊情况 - 一种内置情况。虽然我不相信在常规业务代码中以此方式使用属性是可取的(尽管对于框架代码可能可以接受)。 - Joffrey

0
在我的项目中,我定义了一个通用类型来封装所有标量类型,包括原始类型和用户定义的类型。
     data class pTp<T>(var v: T)  

所以我可以创建

    fun PercAcumNorm(percAcum:pTp<Double>, perc:pTp<Double>, 
              valor:Double, Soma:Double)
    { 
      perc.v = valor/soma
      parcAcum.v += perc.v
    } 

然后只需要调用

   ....
   var pAcum:pTp<Double> = pTp(0.40)
   var p = 0
   var valor = 5
   var soma = 100      
   percCalc(pAcum, p, soma, valor)
   println(pAcum.v)  // it prints 0.45 

这不是最干净的解决方案,但是如果不使用 Kotlin 的内置功能,就只能这样做,而这些功能在未来可能会被修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接