Kotlin中带可选参数重写toString失效,如何用Kotlin风格解决?
Kotlin数据类重写toString的优雅实现(带可选参数)
我尝试为数据类LatLong实现带可选参数的字符串格式化逻辑,但默认的toString()调用和直接打印对象都没有使用自定义逻辑:
data class LatLong( val latitude: Double, val longitude: Double ){ // 编译器不允许用override关键字,因为Any类的toString无参 fun toString(decimals: Int = 5) = "${"%.${decimals}f".format(latitude)}, ${"%.${decimals}f".format(longitude)}" } fun main() { println(LatLong(-123.0, 49.0)) // 输出默认数据类格式:LatLong(latitude=-123.0, longitude=49.0) println(LatLong(-123.0, 49.0).toString()) // 同上,未调用自定义重载函数 println(LatLong(-123.0, 49.0).toString(decimals=5)) // 输出预期格式化结果:-123.00000, 49.00000 }
问题核心
- 自定义的
toString(decimals: Int)是重载而非重写,因此无参toString()仍然调用数据类自动生成的版本 - 直接打印对象会触发无参
toString(),所以也不会执行自定义格式化逻辑
符合Kotlin风格的解决方案
方案1:统一默认值,重写无参toString
将默认小数位数定义为类内常量,避免重复定义,同时重写无参toString()调用带参数的版本:
data class LatLong( val latitude: Double, val longitude: Double ) { companion object { private const val DEFAULT_DECIMALS = 5 } fun toString(decimals: Int = DEFAULT_DECIMALS): String = "${"%.${decimals}f".format(latitude)}, ${"%.${decimals}f".format(longitude)}" override fun toString(): String = toString(DEFAULT_DECIMALS) }
三种调用方式都会使用自定义逻辑:
println(LatLong(-123.0, 49.0))→ 调用重写的无参toString(),使用默认小数位数LatLong(...).toString()→ 同上LatLong(...).toString(3)→ 调用带参数的重载函数,使用指定小数位数
方案2:使用自定义命名的格式化函数(更推荐)
由于toString()在Kotlin/Java中有明确的无参约定,重载它容易造成混淆。更清晰的方式是自定义格式化函数,再重写无参toString()调用它:
data class LatLong( val latitude: Double, val longitude: Double ) { fun toFormattedString(decimals: Int = 5): String = "${"%.${decimals}f".format(latitude)}, ${"%.${decimals}f".format(longitude)}" override fun toString(): String = toFormattedString() }
这种方式的优势:
- 函数名
toFormattedString明确表达格式化意图,避免重载带来的歧义 - 保持
toString()的语义一致性,同时复用格式化逻辑
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

