二级构造语法kotlin

我有一个主要的构造函数下面的kotlin类,

class Person(first: String, last: String, age: Int){ init{ println("Initializing") } } 

我想添加一个二级构造函数,将全名解析为名和姓,并调用主构造函数。 但是,我不能得到正确的语法…

 class Person(first: String, last: String, age: Int){ // Secondary constructor constructor(fullname: String, age: Int): this("first", "last", age) { println("In secondary constructor") } init{ println("Initializing") } } 

这工作正常,因为我没有实际解析二级构造函数中的fullname 。 当我继续尝试解析全名时,

 constructor(fullname: String, age: Int): var first = fullname.split()[0]; ... { println("In secondary constructor") } 

我得到一个未解决的参考:全名。 它不在范围内,但如果我把它放在大括号中,那么我不能通过this调用主构造函数,

 constructor(fullname: String, age: Int): { var first = fullname this(first, "foo", age) println("In secondary constructor") } 

我得到一个涉及缺少invoke函数的错误。

Kotlin文档找不到这种情况的一个很好的例子,对不起。

当我需要在将结果传递给主构造函数之前需要执行某些计算的辅助构造函数时,我使用的解决方案是在伴随对象上的函数。 执行此操作的代码如下所示:

 class Person(first: String, last: String, age: Int) { companion object { fun fromFullNameAndAge(fullname: String, age: Int) : Person { println("In secondary constructor") var bits = fullname.split() // Additional error checking can (and should) go in here. return Person(bits[0],bits[1],age) } } init{ println("Initializing") } } 

你可以像这样使用它

 var p = Person.fromFullNameAndAge("John Doe", 27) 

哪个不像Person("John Doe", 27)那么整洁Person("John Doe", 27)但是IMO并不是太糟糕。

通过this构造函数调用必须是第一个调用。 这就是为什么它作为一个委托来处理,而不是一个普通的方法调用。 这意味着您不能在委托调用之前声明变量。

你可以通过简单地内联任何你计划存储在变量中的值来解决这个问题:

 constructor(fullName : String, age : int) : this(fullName.split(" ")[0], fullName.split(" ")[1]) 

但是,如果没有指定姓氏,或者客户端决定使用-或其他字符作为分隔符,这可能会导致索引越界。 最重要的是,这是一个眼睛疼痛。

设计分析

与你的结构有关的问题是让Person类负责确定名字和姓氏。 这会恶化该类的可重用性,因为它将被限制为一种解析形式。 这就是为什么名称的解析不应该由Person执行的原因。

相反,你应该暴露你的主要构造函数,然后让Person的客户端分隔名和姓。

解决方案示例

想象一下,我们正在从文件中读取名字。 文件中的每一行都包含全名。

 nameFile.forEachLine({ personList.add(Person(it)) }) 

这是你试图给你的客户的奢侈:让他们简单地输入一个名字,而不用担心解析它。

问题在于缺乏安全性:如果该行只包含名字,该怎么办? 如果文件没有使用空白来分隔姓和名? 你将被迫定义新的Person类型来处理不同的名字/姓氏组合。

相反,解析应该在类之外进行:

 file.forEachLine({ val firstName = ... val secondName = ... personList.add(Person(firstName, secondName)) }) 

既然责任已经从Person身上拿走,我们可以把责任交给一个新的对象,如果我们想的话:

 val parser = NameParser(" ") //specify delimiter file.forEachLine({ val firstName = parser.extractFirstName(it) val lastName = parser.extractLastName(it) personList.add(Person(firsrName, lastName)) })