2017-09-22 73 views
3

在我的活動中,我有一個應該是不可空的字段,並有一個自定義setter。我想在我的onCreate方法中初始化該字段,因此我將lateinit添加到了我的變量聲明中。但是,顯然你不能這樣做(目前):https://discuss.kotlinlang.org/t/lateinit-modifier-is-not-allowed-on-custom-setter/1999Kotlin:使用自定義setter時沒有lateinit的解決方法?

這些都是解決辦法,我可以看到:

  • 它做Java的方式。使該字段可以爲空並使用null對其進行初始化。我不想這樣做。
  • 使用類型的「默認實例」初始化該字段。這就是我目前所做的。但是對於某些類型來說這太昂貴了。

有人可以推薦一個更好的方法(不涉及刪除自定義setter)?

+0

是'onCreate'建設者的一部分嗎? –

+1

不,這是一個從Activity類繼承的重寫方法,它是由Android作爲應用程序生命週期的一部分調用的。 – xvlcw

+0

爲什麼你需要一個二傳手?聽起來你可以在這裏改進你的架構。 – tynn

回答

3

與可空屬性支持的屬性替換它:

var _tmp: String? = null 
    var tmp: String 
     get() = _tmp!! 
     set(value) {_tmp=value; println("tmp set to $value")} 

或者這樣,如果你希望它是與lateinit語義一致:

var _tmp: String? = null 
var tmp: String 
    get() = _tmp ?: throw UninitializedPropertyAccessException("\"tmp\" was queried before being initialized") 
    set(value) {_tmp=value; println("tmp set to $value")} 
+0

但我仍然得到一個錯誤,因爲我必須初始化我的屬性 – xvlcw

+0

所以,你想在Kotlin中使用未初始化的屬性,但不希望它爲空或拋出異常? – Pavlus

+0

我試圖應用您的上層解決方案。但是我得到一個錯誤,因爲'tmp'沒有被初始化。 – xvlcw

1

這可以通過使用來實現backing property(根據Pavlus的回答);不過,我更願意把它包裝一個delegate內避免暴露其財產的背景之外:

open class LateInit<T: Any> : ReadWriteProperty<Any?, T> { 
    protected lateinit var field: T 

    final override fun getValue(thisRef: Any?, property: KProperty<*>) = get() 
    final override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = set(value) 

    open fun get() = field 
    open fun set(value: T) { field = value } 
} 

這提供了標準的getter和setter方法,可以用自定義實現覆蓋:

var upperCaseString by object : LateInit<String>() { 
    override fun set(value: String) { 
     field = value.toUpperCase() 
    } 
} 

然而,因爲此實現需要擴展委託,所以不能從屬性類型推斷出泛型。

class LateInit<T: Any>(private val getter: FieldHolder<T>.() -> T = { field }, 
         private val setter: FieldHolder<T>.(T) -> Unit = { field = it }) : 
     ReadWriteProperty<Any?, T> { 
    private val fieldHolder = FieldHolder<T>() 

    override fun getValue(thisRef: Any?, property: KProperty<*>) = fieldHolder.getter() 
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = 
      fieldHolder.setter(value) 

    class FieldHolder<T: Any> { 
     lateinit var field: T 
    } 
} 

然後可以這樣使用:這可以通過採用自定義的getter和setter作爲參數,克服

private var upperCaseString: String by LateInit(setter = { field = it.toUpperCase() }) 
相關問題