如何用if语句优雅检查对象类型是否属于指定类型集合?
更优雅地在if语句中检查密封类子集类型
确实,Kotlin里用when处理密封类的多类型检查简直丝滑,但换到if语句的时候,要么写一串||堆起来,要么用::class in list,总觉得不够优雅。这里有几种更简洁直观的实现方式,帮你把代码变得清爽:
1. 重载in运算符(最推荐)
我们可以给Collection<KClass<out SealedClass>>重载contains运算符,让它直接接收SealedClass实例做检查,这样就能像检查字符串是否在集合里一样写代码,完全对齐你的使用习惯:
// 定义运算符重载 operator fun Collection<KClass<out SealedClass>>.contains(obj: SealedClass): Boolean { return obj::class in this } // 使用方式 if (b in listOf(SealedClass.Subclass1::class, SealedClass.Subclass2::class)) { // 执行你的业务逻辑 }
这种写法可读性拉满,而且自带类型安全——如果传入非密封类子类的KClass,编译器会直接报错,避免低级错误。
2. 封装扩展函数
如果不想修改运算符的默认行为,可以给SealedClass写一个扩展函数,把类型检查逻辑封装起来:
inline fun SealedClass.isOneOf(vararg classes: KClass<out SealedClass>): Boolean { return this::class in classes } // 使用方式 if (b.isOneOf(SealedClass.Subclass1::class, SealedClass.Subclass2::class)) { // 执行你的业务逻辑 }
如果是固定数量的类型检查(比如只检查2种),还可以用reified泛型实现更严格的类型约束:
inline fun <reified T1 : SealedClass, reified T2 : SealedClass> SealedClass.isEither(): Boolean { return this is T1 || this is T2 } // 使用方式 if (b.isEither<SealedClass.Subclass1, SealedClass.Subclass2>()) { // 执行你的业务逻辑 }
3. 预定义子类集合
如果某个子类子集需要被多次复用,建议在密封类的伴生对象里预定义这个集合,复用性更高:
sealed class SealedClass { class Subclass1 : SealedClass() class Subclass2 : SealedClass() class Subclass3 : SealedClass() companion object { // 预定义常用的子类集合 val targetSubclasses = setOf(Subclass1::class, Subclass2::class) } } // 结合运算符重载的使用方式 if (b in SealedClass.targetSubclasses) { // 执行你的业务逻辑 } // 或者不用运算符的写法 if (b::class in SealedClass.targetSubclasses) { // 执行你的业务逻辑 }
这些方式都能让if语句里的类型检查变得简洁优雅,选择哪种取决于你的使用场景——偶尔检查用运算符重载最直观,频繁复用则预定义集合更高效。
内容的提问来源于stack exchange,提问作者Konstantin Raspopov
相关产品推荐
相关产品推荐

