我正在尝试创建一个交换函数,该函数需要两个参数,如下所示:
fun swap(a :Int, b:Int) {
}
我这样称呼它:
var a = 10
var b = 5
swap(a,b)
// a should be 5
// b should be 10
问题在于,即使我在交换函数中交换值,也不会反映在调用方,因为它是作为副本而不是作为引用传递的。
无论如何,是否有将值类型传递给交换函数并允许函数更改它们的能力。
答案 0 :(得分:1)
我知道OP并没有要求这样做,但是idiomatic Kotlin看起来像这样:
var a = 1
var b = 2
a = b.also { b = a }
答案 1 :(得分:0)
看起来像Kotlin的行为非常类似于Java: Is Kotlin "pass-by-value" or "pass-by-reference"?
交换的简单方法是设置支持类
private fun swap(pair: Pair) {
pair.a += pair.b
pair.b = pair.a - pair.b
pair.a = pair.a - pair.b
}
private data class Pair(var a: Int, var b: Int)
fun main() {
val pair = Pair(10, 5)
swap(pair)
println(pair)
}
答案 2 :(得分:0)
绝对没有办法直接做到这一点。 Kotlin 复制标量类型(Double
,Float
,Boolean
,Int
等的值)。因此,所有内部更改都将丢失。
对于任何其他类型,Kotlin复制传递给该函数的参数的引用。因此,参数的任何属性/字段更改都会更改调用方参数。
无法更改此行为。
尝试了许多方法以克服通过引用传递标量的可能性,例如 Kotlin , Java 和其他一些语言;正如上面的注释所建议的那样,我目前的策略是对任何标量类型使用普通的和通用的包装。
最近,我对所有东西都使用了这个技巧,包括在一个函数内部,否则该函数将要求我返回多个值。另一种方法是将返回值加入人工类或解构声明中:val (a, b, c) = function-call()
语法。但是,我讨厌关节类,并且解构声明仅适用于局部变量,当某些组件需要当前命令块之外的可见性时,这很烦人。
我的代码很简单:
data class p<T>( // It's a generic wrap class for scalar type T
var v:T
)
fun <T>swap(a:p<T>, b:p<T>){ // It's a generic swap for scalar types
var aux:p<T> = a.copy()
a.v = b.v
b.v =aux.v
}
fun main() {
var a:p<Int> = p<Int>(2) // 'a' is a kind of 'Int' variable
var b:p<Int> = p<Int>(3) // and so is 'b'
swap(a,b) // Exchange 'a' and 'b' values
println(a.v) // 3
println(b.v) // 2
}
唯一的缺点是无法使用实标量类型的语法糖。
我必须在使用标量变量时添加.v
。
我仅将其用于需要在某些函数中通过引用传递的变量,这种情况并不常见。我会尽可能避免附带影响。
答案 3 :(得分:0)
您可以拥有一个获取变量引用的函数
var x = 10
var y = 20
fun main() {
println("x=$x, y=$y") // x=10, y=20
swap(::x, ::y)
println("x=$x, y=$y") // x=20, y=10
}
fun <T> swap(firstRef: KMutableProperty0<T>, secRef: KMutableProperty0<T>) {
val temp = firstRef.get()
firstRef.set(secRef.get())
secRef.set(temp)
}
,您可以传递类似swap(someClass::x, someClass::y)
唯一的限制是您不能传递不是世界末日的局部变量的引用。
如果您不喜欢凌乱的语法,则可以随时定义一个typealias
并使其美观:
typealias Ref<T> = KMutableProperty0<T>
fun <T> swap(firstRef: Ref<T>, secRef: Ref<T>) {
...
}