为什么属性初始化器不会调用自定义setter?

从Kotlin文档中,允许自定义setter:

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

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

但是你不能拥有一个没有自定义getter的自定义setter(并且从init块初始化):

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

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

虽然你可以有一个自定义的getter没有自定义setter,但没有问题在这里:

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

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

那么为什么你不能使用一个自定义setter来初始化init块中的属性,为什么init块会在属性初始值设定项直接分配的时候调用自定义setter,绕过了自定义setter?

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) { }
}

属性初始值设定项不会调用自定义设置项,因为它们的目的是提供默认值。

与Java不同的是,在Kotlin中,不仅局部变量必须在第一次访问之前被初始化,但是类属性也必须被初始化。

在Java中这是有效的。

public class Test {
    public String str;

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

在Kotlin中,这不是。

class Parent {
    var str: String?
}

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

由于这个原因,自定义setter需要通过属性初始值设定项或构造函数来初始化其属性。 看看下面的例子。

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实例,而不调用setter。 然后调用init块并使用setter将值设置为“b” 。 然后使用setter来“c”

链接地址: http://www.djcxy.com/p/94259.html

上一篇: Why don't property initializers call a custom setter?

下一篇: Xcode 8.2 & 8.1 crashes when enlarging any view in storyboard