Kotlin:可转让的“它”?

我试图简化Kotlin中的Parcelable代码:

public class C() : Parcelable { var b1: Boolean = false var b2: Boolean = false var b3: Boolean = false var i1: Int = 0 var i2: Int = 0 val parcelBooleans = listOf(b1, b2, b3) val parcelInts = listOf(i1, i2) override fun writeToParcel(p: Parcel, flags: Int) { parcelBooleans.forEach { p.writeBoolean(it) } parcelInts.forEach { p.writeInt(it) } } private fun readFromParcel(p: Parcel) { parcelBooleans.forEach{ it = p.readBoolean() } // does not compile as "it" is a "val" } // ... parcel creator bla bla } 

writeBoolean()和readBoolean()是扩展函数。

有没有办法让forEach列表上有一个可分配的“it”?

更新:作者 在其中一个答案的评论中澄清了这个问题:

我的观点是,我的名单是不可变的,里面的元素是。 元素是我的属性。 但是我意识到,也许listOf正在为我的属性创建一个值副本…所以要么我必须依靠反射,或者将基本类型封装到类中以允许改变它们的值。

意图是通过只读列表parcelBooleans ,其中引用b1b2b3修改了b1b2b3的值; 但不能改变列表本身。

更新: KT-7033已经修复,现在这个答案不需要kotlin-reflect.jar

我认为简单的方法来实现你想要的是使用属性的引用 ,但要注意的是,比你应该提供kotlin-reflect.jar在类路径(直到KT-7033不固定)。 此外, KT-6947固定后可能会简化。

 public class C_by_Reflection() : Parcelable { var b1: Boolean = false var b2: Boolean = false var b3: Boolean = false var i1: Int = 0 var i2: Int = 0 val parcelBooleans = listOf(::b1, ::b2, ::b3) val parcelInts = listOf(::i1, ::i2) override fun writeToParcel(p: Parcel, flags: Int) { parcelBooleans.forEach { p.writeBoolean(it.get(this)) } parcelInts.forEach { p.writeInt(it.get(this)) } } private fun readFromParcel(p: Parcel) { parcelBooleans.forEach{ it.set(this, p.readBoolean()) } } // ... parcel creator bla bla } 

另一个简单的解决方案是使用委托属性 :

 public class C_by_Delgates() : Parcelable { val mapBooleans = hashMapOf<String, Any?>() var b1: Boolean by mapBooleans var b2: Boolean by mapBooleans var b3: Boolean by mapBooleans val mapInts = hashMapOf<String, Boolean>() var i1: Int by mapInts var i2: Int by mapInts override fun writeToParcel(p: Parcel, flags: Int) { mapBooleans.forEach { p.writeBoolean(it.value as Boolean) } mapInts.forEach { p.writeInt(it.value as Int) } } private fun readFromParcel(p: Parcel) { mapBooleans.forEach { mapBooleans[it.key] = p.readBoolean() } } // ... parcel creator bla bla } 

注意: 问题不清楚作者是否试图通过列表中的引用来改变属性b1b2b3 或者,如果他正试图修改名单parcelBooleans的内容,这是属性值的副本。 如果第一个,看到@Bashor的答案(或者只是让列表的值是可变的子内容),如果第二个答案是正确的。

考虑到在这个其他堆栈溢出问题中定义的扩展函数“如何在迭代时修改列表的内容”,您可以将代码更改为:

 public class C() : Parcelable { var b1: Boolean = false var b2: Boolean = false var b3: Boolean = false var i1: Int = 0 var i2: Int = 0 // CHANGED: use mutable list, array, or primitive array val parcelBooleans = arrayListOf(b1, b2, b3) val parcelInts = listOf(i1, i2) override fun writeToParcel(p: Parcel, flags: Int) { parcelBooleans.forEach { p.writeBoolean(it) } parcelInts.forEach { p.writeInt(it) } } private fun readFromParcel(p: Parcel) { // CHANGED: using the extension function parcelBooleans.mapInPlace { p.readBoolean() } } // ... parcel creator bla bla } 

创建你自己的Iterator将是OOP的方式。

如果你想更有效的方式,你可以使用map(),例如

 private fun readFromParcel(p: Parcel) { val mappedBooleans = parcelBooleans.map{ p.readBoolean() } } 

map()类似于forEach,它使用每个lambda执行的返回值来创建一个新的List <>

一种方法是映射每个值:

 parcelBooleans = parcelBooleans.map{ p.readBoolean() } 

parcelBooleans你还得把parcelBooleans一个可变的变量。

发现我的代码起初不能工作,因为listOf复制了属性的值。

所以我使用get / set方法将基本类型包装在一个简单的类中:

 public class MBoolean() { var internal: Boolean = false constructor(b: Boolean) : this() { internal = b } fun set(b: Boolean) { internal = b } fun get(): Boolean { return internal } } public class MInt() { private var internal: Int = 0 constructor(i: Int) : this() { set(i) } public fun set(i: Int) { internal = i } public fun get(): Int { return internal } } override fun writeToParcel(p: Parcel, flags: Int) { parcelBooleans.forEach { p.writeBoolean(it.get()) } parcelInts.forEach { p.writeInt(it.get()) } } private fun readFromParcel(p: Parcel) { parcelBooleans.forEach { it.set(p.readBoolean()) } parcelInts.forEach { it.set(p.readInt()) } }