Kotlin 为什么不';属性初始值设定项调用自定义设置项?

Kotlin 为什么不';属性初始值设定项调用自定义设置项?,kotlin,Kotlin,从中,允许自定义设置程序: class Test { var stringRepresentation: String get() = field set(value) { setDataFromString(value) } init { stringRepresentation = "test" } private fun setDataFromString(value: String) { } } 但是,如果没有自定义ge

从中,允许自定义设置程序:

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

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}
但是,如果没有自定义getter(并从
init
块初始化),则不能有自定义setter:

虽然您可以使用自定义getter而不使用自定义setter,但这里没有问题:

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

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}
那么,为什么不能在
init
块中使用具有初始化属性的自定义setter,为什么
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) { }
}

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

与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
}
类父类{
var-str:String?
}
趣味主线(args:Array){
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
}
类测试{
var stringRepresentation:String=“a”//默认值。不调用自定义setter
get()=字段
设置(值){
println(“将stringRepresentation属性设置为%s。当前值为%s.”。格式(值,字段))
字段=setDataFromString(值)
}
初始化{
this.stringRepresentation=“b”//调用自定义setter
}
私有fun setDataFromString(值:String):String{
println(“将stringRepresentation属性设置为%s.”格式(值))
返回值
}
}
趣味主线(args:Array){
Test().stringRepresentation=“c”//Calls自定义setter
}
属性stringRepresentation在不调用setter的情况下初始化为其类的实例化。 然后调用init块并使用setter将值设置为“b”
然后使用setter“c”

只是有点难以理解为什么添加带有
init
块属性初始化的自定义setter将无法编译(因为属性正在初始化)。有没有一种方法可以避免初始值设定项和自定义设置项中的代码重复,而不必委托给其他方法?我想在初始化过程中做一些工作,避免两次写入属性。无论何时调用
set
,都需要做同样的工作。init block会初始化属性。但是,由于属性有一个自定义setter,init块使用此自定义setter来执行此操作。由于自定义setter要求使用默认值或由构造函数初始化属性,因此您需要提供其中之一。Kotlin似乎是一种很好的语言,但在某些地方,它离不开一勺屎。。。(@breandan,您可以通过将值初始化为某个随机值来避免重复,只是为了满足此要求。然后在构造函数初始值设定项块中,您可以通过设置属性值来实际初始化属性值,这将调用自定义设置项。例如,您可以将字符串初始化为“”在属性初始值设定项中,使用
init{}
block在属性下方,该属性使用传入构造函数的值再次设置属性,并调用setter代码。尽管这样做有效,但这似乎是语言设计中的一个缺陷。@still\u\u\u 1是的,谢谢你的回答。这是我试图避免的,重复初始化。但这似乎是必要的案例
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
}