Reputation: 1109
I'm pretty new on Kotlin and I've been stuck on making a data class similar to this Swift struct:
struct AppVersion {
let major: Int
let minor: Int
let patch: Int
}
extension AppVersion {
init(version: String) {
let parts = version.split(separator: ".")
let numbers = parts.map { Int($0) ?? 0 }
self.init(major: numbers[0], minor: numbers[1], patch: numbers[2])
}
}
For the sake of clarity we'll just assume toInt()
doesn't throw and there are always 3 components in the version string.
I have two solutions that work. Using a companion object:
data class AppVersion (val major: Int, val minor: Int, val patch: Int) {
companion object {
fun fromString(version: String): AppVersion {
val parts = version.split(".").map { it.toInt() }
return AppVersion(parts[0], parts[1], parts[2])
}
}
}
Or writing something that looks really bad:
data class AppVersion (val major: Int, val minor: Int, val patch: Int) {
constructor(version: String) : this(
version.split(".")[0].toInt(),
version.split(".")[1].toInt(),
version.split(".")[2].toInt()
)
}
But having a longer method name for a convenience constructor seems weird and the second option is just bad.
Is something like this possible ?
data class AppVersion (val major: Int, val minor: Int, val patch: Int) {
constructor(version: String): this(0, 0, 0) {
val parts = version.split(".").map { it.toInt() }
this(parts[0], parts[1], parts[2])
}
}
Upvotes: 1
Views: 1340
Reputation: 97138
A super constructor call must be the first statement of a constructor, and can be present only once. Also, each val
must be initialized exactly once; you can't initialize it with 0 and then change your mind. This is a JVM restriction.
The idiomatic solution in Kotlin is to use a factory method, as in your first solution.
Upvotes: 1