2015-06-25 16 views
9

creo un Kotlin classe con un attributo di classe, che voglio inizializzare nel costruttore:Kotlin: inizializzare attributo di classe nel costruttore

public class TestClass { 

    private var context : Context? = null // Nullable attribute 

    public constructor(context : Context) { 
     this.context = context 
    } 

    public fun doSomeVoodoo() { 
     val text : String = context!!.getString(R.string.abc_action_bar_home_description) 
    } 
} 

Purtroppo devo dichiarare l'attributo come Nullable con il "? " firmare, anche se l'attributo verrà inizializzato nel costruttore. La dichiarazione di questo attributo come attributo Nullable rende sempre necessario forzare un valore Non Null con "!!" o per fornire un controllo Null con "?".

C'è un modo per evitarlo, se l'attributo di classe sarà inizializzato nel costruttore? Vorrei apprezzare una soluzione come questa:

public class TestClass { 

    private var context : Context // Non-Nullable attribute 

    public constructor(context : Context) { 
     this.context = context 
    } 

    public fun doSomeVoodoo() { 
     val text : String = context.getString(R.string.abc_action_bar_home_description) 
    } 
} 
+0

Il secondo esempio sta lavorando con Kotlin 0.12.213. Che versione di Kotlin stai usando? – D3xter

+0

Funziona. Ho già usato 0.12.613. Ma penso, stavo facendo qualcosa di sbagliato. Scusate! – Christopher

+0

Ci sono più casi disponibili, ho aggiunto una risposta per una copertura completa. –

risposta

11

Se l'unica cosa che si sta facendo nel costruttore è un incarico, allora si potrebbe utilizzare il costruttore principale con una proprietà privata.

es:

public class TestClass(private var context: Context) { 

    public fun doSomeVoodoo() { 
    val text = context.getString(R.string.abc_...) 
    } 
} 
+1

oh, bello! Non lo sapevo! – Christopher

14

Come dimostrato dalla D3xter si ha la possibilità di impostare nel costruttore. Hai anche altre opzioni. Qui tutti sono ...

creare la proprietà all'interno del costruttore (come da @ D3xter), questo è il caso più comune per le proprietà semplici inizializzati direttamente dal costruttore principale:

class TestClass(private val context: Context) { 
    fun doSomeVoodoo() { 
     val text : String = context.getString() 
    } 
} 

È possibile dichiarare la proprietà val e non inizializzarla, supponendo che tutti i possibili costruttori lo inizino effettivamente (come nel secondo esempio nella domanda che si sta facendo). Questo è normale quando si dispone di più di un costruttore che potrebbe inizializzare un valore diverso:

public class TestClass { 
    private val context: Context 

    public constructor(context : Context) { 
     this.context = context 
    } 

    // alternative constructor 
    public constructor(pre: PreContext) { 
     this.context = pre.readContext() 
    } 

    public fun doSomeVoodoo() { 
     val text : String = context.getString() 
    } 
} 

È possibile passare in parametri del costruttore che non sono dichiarazioni di proprietà, e quindi utilizzare quelli all'interno inizializzazioni di proprietà. Questo è comune quando si dispone di inizializzazione più complessi o necessità di utilizzare le proprietà delegati:

class TestClass(context: PreContext) { 
    private val context : Context by lazy { context.readContext() } 
    private val other: List<Items> = run { 
     context.items.map { it.tag }.filterNotNull() 
    } 
    private val simpleThing = context.getSimple() 

    fun doSomeVoodoo() { 
     val text : String = context.getString() 
    } 
} 

Utilizzando lateinit modifier quando non è possibile inizializzare il valore durante la costruzione, ma si è sicuri che sarà fatto prima del primo accesso in lettura. Questo è comune quando un'iniezione di dipendenza, contenitore CIO, o qualcosa del genere crea una versione vuota della classe e poi inizializza immediatamente:

class TestClass() { 
    private lateinit var context : Context // set by something else after construction 

    fun doSomeVoodoo() { 
     val text : String = context.getString() 
    } 
} 

Per lateinit la proprietà deve attualmente essere un var e non funziona con primitiva tipi.

È anche possibile dichiarare una proprietà var e non inizializzarla se si utilizza un delegato progettato a tale scopo, ad esempio Delegates.notNull().Questo è simile a lateinit e comune quando si desidera un var che non ha stato iniziale, ma è impostato più tardi, dopo la costruzione al punto sconosciuto in tempo:

public class TestClass() { 
    private var context: Context by Delegates.notNull() 

    public fun doSomeVoodoo() { 
     // if context is not set before this is called, an exception is thrown 
     val text : String = context.getString() 
    } 
}