2016-12-19 2 views
7

Из Kotlin documentation, пользовательские сеттеров допускаются:Почему инициализаторы свойств не вызывают пользовательский сеттер?

class Test { 
    var stringRepresentation: String 
    get() = field 
    set(value) { 
     setDataFromString(value) 
    } 

    init { 
    stringRepresentation = "test" 
    } 

    private fun setDataFromString(value: String) { } 
} 

Но вы не можете иметь пользовательский сеттер без пользовательского геттера (и инициализации от init блока):

class Test { 
    // Compilation error: "Property must be initialized" 
    var stringRepresentation: String 
    set(value) { 
     setDataFromString(value) 
    } 

    init { 
    stringRepresentation = "test" 
    } 

    private fun setDataFromString(value: String) { } 
} 

Хотя вы можете иметь пользовательский геттер без настраиваемого сеттера, здесь нет проблем:

class Test { 
    var stringRepresentation: String 
    get() = field 

    init { 
    stringRepresentation = "test" 
    } 

    private fun setDataFromString(value: String) { } 
} 

Так почему бы вам не использовать ac ustom с свойством, инициализированным из блока init, и почему блок init вызывает пользовательский сеттер, в то время как инициализатор свойств назначает напрямую, минуя настраиваемый сеттер?

class Test { 
    var stringRepresentation: String = "" // Does not call custom setter 
    set(value) { 
     setDataFromString(value) 
    } 

    init { 
    stringRepresentation = "test" // Calls custom setter 
    } 

    private fun setDataFromString(value: String) { } 
} 

ответ

4

Инициализаторы свойств не вызывают пользовательский сеттер, поскольку их цель - предоставить значение по умолчанию.

В отличие от Java, в Kotlin не только локальные переменные должны быть инициализированы до их первого доступа, но и свойств класса.

В Java это действительное.

public class Test { 
    public String str; 

    public static void main(String[] args) { 
     System.out.println(new Test().str); 
    } 
} 

В Котлине это не так.

class Parent { 
    var str: String? 
} 

fun main(args: Array<String>) { 
    Parent().str 
} 

По этой причине пользовательскому сетевому устройству необходимо, чтобы его свойство инициализировалось либо инициализатором свойств, либо конструктором. Взгляните на следующий пример.

class Test { 
    var stringRepresentation: String = "a" // Default value. Does not call custom setter 
     get() = field 
     set(value) { 
      println("Setting stringRepresentation property to %s. Current value is %s.".format(value, field)) 
      field = setDataFromString(value) 
     } 

    init { 
     this.stringRepresentation = "b" // Calls custom setter 
    } 

    private fun setDataFromString(value: String): String { 
     println("Setting stringRepresentation property to %s.".format(value)) 
     return value 
    } 
} 

fun main(args: Array<String>) { 
    Test().stringRepresentation = "c" // Calls custom setter 
} 

Свойство stringRepresentation инициализируется «а» OPON экземпляра своего класса без вызова сеттера. Затем вызывается блок init и задает значение «b» с использованием сеттера. Затем "c" используя сеттер.

+2

Просто с пониманием, почему добавление пользовательского сеттера с инициализацией свойства блока init не будет скомпилировано (поскольку свойство * инициализируется *). Есть ли способ избежать дублирования кода в инициализаторе и настраиваемом сетевом устройстве без передачи другому методу? Я хотел бы выполнить некоторую работу во время инициализации и избежать записи в свойство дважды. Такая же работа должна выполняться всякий раз, когда вызывается 'set'. – breandan

+0

Ну, блок init инициализирует свойство. Но поскольку свойство имеет собственный блок initter, для этого используется этот настраиваемый набор. И поскольку пользовательский сеттер требует, чтобы свойство было инициализировано либо значением по умолчанию, либо конструктором, вам необходимо предоставить один из них. – Januson

+0

О дублировании ... частный метод - самый простой способ. Но это зависит от вашего варианта использования. – Januson

Смежные вопросы