2015-04-26 3 views
0

Я пытаюсь упростить Parcelable код в Котлин:Kotlin: назначается «это»?

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»?

Update:в комментарии к одному из ответов автор разъясняет этот вопрос как:

Я считаю, что мой список не является изменяемым, элементы внутри есть. Элементы - это мои свойства. Но я понимаю, что, возможно, listOf делает копию значений моих свойств ... так что либо я должен полагаться на отражение, либо обернуть базовый тип в класс, чтобы позволить изменять их значение.

Намерение осуществляется через список только для чтения parcelBooleans который содержит ссылки на b1, b2 и b3 изменять значения b1, b2 и b3; но не мутирует сам список.

+0

Привет. Попробуйте это: http://stackoverflow.com/questions/5849154/can-we-write-our-own-iterator-in-java (реализовать свой собственный итератор: http://docs.oracle.com/javase/6/ docs/api/java/util/Iterator.html) – Totoo

+0

Вы можете создать свой собственный Iterator в качестве метода расширения для списка <>, например forMutableEach {} – D3xter

+0

Это было бы лучше, если бы вы написали вопрос как единичный тест с утверждениями, поэтому цель понятна. Вы пытаетесь обновить 'b1',' b2', 'b3' через свои ссылки в списке? Или вы просто пытаетесь обновить значения списка в 'parcelBooleans' до новых значений. Если первый, то ответ от Башора. Если второй, то ответ от меня. Вы должны обновить свой вопрос, чтобы быть понятным (я думаю, что чтение каждого комментария ниже помогает, но это не очень удобно) –

ответ

3

Обновление:KT-7033 было зафиксировано, что этот ответ сейчас работает, не требуя kotlin- reflect.jar

Я думаю, что простой способ для достижения ваших желаний является использование property references, но учтите, что чем вы должны предоставить Котлин-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 
} 

Другим простым решением является использование delegated properties:

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 
} 
+0

Я не знал о делете mapVar, это аккуратно: D Я хочу избежать банки, как и для Android. –

+0

@Geobert - Это действительно лучший ответ, https: //youtrack.jetbrains.com/issue/KT-7033 был исправлен, поэтому рефлекторная банка больше не нужна. –

-1

способ сделать это состоит в отображении каждого значения:

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

Вы должны сделать parcelBooleans изменяемая переменная, хотя.

+0

Я хочу сказать, что мой список не изменчив, элементы внутри. Элементы - это мои свойства. Но я понимаю, что, возможно, listOf делает копию значений моих свойств ... так что либо я должен полагаться на отражение, либо обернуть базовый тип в класс, чтобы позволить изменять их значение. –

+0

Просто сделал быстрый тест: весело основные (арг: Array ) { вар b1: Boolean = ложь вар b2: Boolean = ложь вал Blist = listOf (b1, b2) b1 = истинный println (bList) } –

+0

@Geobert, вы правы в 'listOf', копируя свои свойства. Это справедливо и для чистой Java. –

-1

Создание собственного Итератора было бы способом ООП для этого.

Если вы хотите перейти более функциональным способом, вы можете использовать map(), например.

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

карта() похожа на Foreach, он использует возвращаемое значение каждого исполнения лямбды, чтобы создать новый список <>

+0

Но это не изменит значение моих свойств (см. Мой комментарий к Egor N answer) –

+0

Для чего этот класс? – D3xter

+0

это делает копию значений, а не на месте мутации. –

-2

Найдено, что мой код на первом не может работать как 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()) } 
} 
+0

Я думаю, вы можете упростить его до класса class (var value: T) ' – bashor

+1

Другие замечания: # вместо этого иметь два конструктора. Вы можете использовать аргументы по умолчанию в основном конструкторе. # Вы можете объявлять поля в первичных конструкторах (см. Предыдущий комментарий). # Свойства объявлений в Kotlin безопасны, потому что это не поле, как на Java, и вы можете в любое время объявить пользовательские геттеры и сеттеры. – bashor

+0

Я сделал общий MType да, но изменил все для решения делегирования mapVar –

0

Примечание:вопрос не ясно, если автор пытается мутировать свойства b1, b2, b3 через ссылку в список. Или если он пытается изменить содержимое списка parcelBooleans, который является копией значений из свойств. Если первый, см. Ответ от @Bashor (или просто введите значения списка, то что-то, что является суб-содержимым, изменено), если во-вторых, этот ответ правильный.

Учитывая функции расширения, определенные в этом другом переполнением стека вопрос "how do you modify the contents of a list while iterating" вы можете изменить свой код, чтобы просто:

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 
} 
Смежные вопросы