Kotlin中修改内联类构造器传入参数的最简方案
优雅实现Kotlin内联类Trimmed,确保字符串始终已修剪
我希望在Kotlin中通过内联类(inline class)实现一个包装String的Trimmed值类,要求所有实例的字符串都满足s == s.trim()。
最初尝试的直接写法无法运行:
@JvmInline value class Trimmed private constructor(val str: String) { constructor(s : String) : super(s.trim()) // 写法无效 }
包括this(s.trim())在内的其他直接修改方式也都不生效。
这个问题的核心限制有这些:
- Kotlin没有便捷方式让内联类的主构造器过滤或修改传入的字符串
- 主构造器设为私有后,无法声明另一个签名完全相同(接收单个String参数)的构造器
- 普通类可以在
init块中修改属性值,但内联类不允许这么做(且String本身不可变,无法直接修改str的内容) - 尝试在同一文件中定义同名工厂函数,但无法访问私有构造器
- 在伴生对象中定义同名工厂函数时,Kotlin会默认解析为递归调用自身,而非类构造器,只能通过文件私有
typealias绕开,但这种方式不够优雅:
typealias Trimmed2 = Trimmed @JvmInline value class Trimmed private constructor(val str: String) { init { assert(str == str.trim()) } companion object { // Kotlin不允许在伴生对象内定义typealias fun Trimmed(s: String): Trimmed = Trimmed2(s.trim()) // 避免递归调用 } }
另一种可行但不够优雅的方案是使用带哑元参数的私有构造器,不过需要添加抑制未使用参数的注解:
@JvmInline value class Trimmed private constructor(val str: String) { private constructor (untrimmed: String, @Suppress("UNUSED_PARAMETER") dummy: Unit) : this(untrimmed.trim()) init { assert(str == str.trim()) } companion object { fun Trimmed(s: String): Trimmed = Trimmed(s, Unit) } }
有没有更简洁优雅的实现方式?比如通过语法明确告知Kotlin,伴生函数要调用的是类构造器而非自身,从而无需使用哑元参数?
需求目标
- 外部代码必须能以普通类的方式构造实例:
Trimmed("abc"),不能使用of/trimmedOf这类命名的工厂函数或其他替代语法 - 绝对不能构造出包含未修剪字符串的实例,外部代码和
Trimmed类自身都能完全信任str始终是已修剪的状态
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

