尽量避免使用带有copy方法的数据类来分配新对象



我有以下数据类

data class Passport(
val byr: String = "",
val iyr: String = "",
val eyr: String = "",
val hgt: String = "",
val hcl: String = "",
val ecl: String = "",
val pid: String = "",
val cid: String = ""
)

我有这个枚举类

enum class PassportFields(val field: String) {
BYR("byr"),
IYR("iyr"),
EYR("eyr"),
HGT("hgt"),
HCL("hcl"),
ECL("ecl"),
PID("pid"),
CID("cid")
}

我有这个方法可以创建个人护照,但我必须使用when语句。

我想避免的是有可变的passportData,我真的很想有这样的val passportData = ....。但是,如果我想做这样的事情,我不能使用.copy(...)进行分配

我还希望避免每次都使用副本来分配新对象。

passportData = passportData.copy(byr = field)

这是我的方法

fun List<String>.parsePassports(): List<Passport> {
return this.map { passportField ->
val passport = passportField.split("n", " ")

var passportData = Passport()
passport.map { field ->
when(field) {
PassportFields.BYR.field -> {
passportData = passportData.copy(byr = field)
}
PassportFields.IYR.field -> {
passportData = passportData.copy(iyr = field)
}
PassportFields.EYR.field -> {
passportData = passportData.copy(eyr = field)
}
PassportFields.HGT.field -> {
passportData = passportData.copy(hgt = field)
}
PassportFields.HCL.field -> {
passportData = passportData.copy(hcl = field)
}
PassportFields.ECL.field -> {
passportData = passportData.copy(ecl = field)
}
PassportFields.PID.field -> {
passportData = passportData.copy(pid = field)
}
PassportFields.CID.field -> {
passportData = passportData.copy(cid = field)
}
}
}
passportData
}
}

===更新===

fun List<String>.parsePassportsV3(): List<Passport> {
return map { passportField ->
val listOfPassport = passportField.split("n", " ").associateBy { it.substringBefore(":") }
.mapValues {
it.value.substringAfter(":")
}
Passport(
byr = listOfPassport.getOrDefault(PassportFields.BYR.field, ""),
iyr = listOfPassport.getOrDefault(PassportFields.IYR.field, ""),
eyr = listOfPassport.getOrDefault(PassportFields.EYR.field, ""),
hgt = listOfPassport.getOrDefault(PassportFields.HGT.field, ""),
hcl = listOfPassport.getOrDefault(PassportFields.HCL.field, ""),
ecl = listOfPassport.getOrDefault(PassportFields.ECL.field, ""),
pid = listOfPassport.getOrDefault(PassportFields.PID.field, ""),
cid = listOfPassport.getOrDefault(PassportFields.CID.field, ""),
)
}
}

您不想创建任何额外的对象,但也希望Passport属性为vals。这意味着在调用Passport的构造函数之前,必须准备好字段的所有值。您不能创建一个创建了一半的passport,然后在列表passport上循环时逐渐为其分配内容。

幸运的是,可以很容易地计算每个passport字段f的值:如果列表passport包含f,则该值为f,否则为""

因此:

fun List<String>.parsePassports(): List<Passport> {
return this.map { passportField ->
val passport = passportField.split("n", " ").toSet()
Passport(
PassportFields.BYR.field.takeIf(passport::contains) ?: "",
PassportFields.IYR.field.takeIf(passport::contains) ?: "",
PassportFields.EYR.field.takeIf(passport::contains) ?: "",
PassportFields.HGT.field.takeIf(passport::contains) ?: "",
PassportFields.HCL.field.takeIf(passport::contains) ?: "",
PassportFields.ECL.field.takeIf(passport::contains) ?: "",
PassportFields.PID.field.takeIf(passport::contains) ?: "",
PassportFields.CID.field.takeIf(passport::contains) ?: "",
)
}
}

可以把它放在一个循环中,但我实际上发现它可读性较差:

val arguments = PassportFields.values().map { 
it.field.takeIf(passport::contains) ?: ""
}
Passport(
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5],
arguments[6],
arguments[7],
)
data class Passport(
val byr: String = "",
val iyr: String = "",
val eyr: String = "",
val hgt: String = "",
val hcl: String = "",
val ecl: String = "",
val pid: String = "",
val cid: String = ""
)
fun List<String>.parsePassports(): List<Passport> {
return this.map { passportString ->
val parts = passportString
.split("n", ":")
.chunked(2)
.groupBy { it.first() }
.mapValues { (_, value) -> value[0][1] }
Passport(
byr = parts["byr"]?: "",
iyr = parts["iyr"]?: "",
eyr = parts["eyr"]?: "",
hgt = parts["hgt"]?: "",
hcl = parts["hcl"]?: "",
ecl = parts["ecl"]?: "",
pid = parts["pid"]?: "",
cid = parts["cid"]?: ""
)
}
}
val data = listOf(
"byr:2001niyr:2019neyr:2029nhgt:185nhcl:#cfa07dnecl:blunpid:000123456ncid:147",
"byr:1965niyr:2015neyr:2025nhgt:177nhcl:#afb90bnecl:ambnpid:123456789ncid:78",
)
val result = data.parsePassports()
println(result)
fun List<String>.parsePassportsV3(): List<Passport> {
return map { passportField ->
val listOfPassport = passportField.split("n", " ").associateBy { it.substringBefore(":") }
.mapValues {
it.value.substringAfter(":")
}
Passport(
byr = listOfPassport.getOrDefault(PassportFields.BYR.field, ""),
iyr = listOfPassport.getOrDefault(PassportFields.IYR.field, ""),
eyr = listOfPassport.getOrDefault(PassportFields.EYR.field, ""),
hgt = listOfPassport.getOrDefault(PassportFields.HGT.field, ""),
hcl = listOfPassport.getOrDefault(PassportFields.HCL.field, ""),
ecl = listOfPassport.getOrDefault(PassportFields.ECL.field, ""),
pid = listOfPassport.getOrDefault(PassportFields.PID.field, ""),
cid = listOfPassport.getOrDefault(PassportFields.CID.field, ""),
)
}
}

最新更新