Kotlin 密封类的作用和方法
本文讲解 Kotlin 密封类的作用和用法。
定义一个 Result 接口,用于表示某个操作的执行结果,然后定义两个类去实现 Result 接口:
interface Result
/**
* 表示成功时的结果
*/
class Success(val msg: String) : Result
/**
* 表示失败时的结果
*/
class Failure(val error: Exception) : Result
定义一个 getResultMsg() 函数,用于获取最终执行结果的信息:
fun getResultMsg(result: Result) = when (result) {
is Success -> result.msg
is Failure -> result.error.message
else -> throw Exception()
}
getResultMsg() 函数中接收一个 Result 参数,通过 when 语句来判断,如果 Result 属于 Success,那么就返回成功信息;如果 Result 属于 Failure,那么就返回错误信息。
但是我们不得不在编写一个 else 条件,否则 Kotlin 编译器会认为这里缺少条件分支,代码将无法编译通过:
'when' expression must be exhaustive, add necessary 'else' branch
但实际上 Result 的执行结果只可能是 Success 或 Failure,这个 else 条件是永远走不到的,所以这里直接抛出了一个异常,只是为了满足 Kotlin 编译器的语法检查而已。另外,编写 else 条件还有一个潜在的风险。如果我们现在新增了一个 Unknown 类并实现 Result 接口,用于表示未知的执行结果,但是忘记在 getResultMsg() 函数中添加相应的条件分支,编译器在这种情况下是不会提醒我们的,而是会在运行的时候进入 else 条件里面,从而抛出异常导致程序崩溃。Kotlin 的密封类就很好地解决了这个问题。
密封类 sealed class
将 Result 接口改造成密封类的写法:
sealed class Result /** * 表示成功时的结果 */ class Success(val msg: String) : Result() /** * 表示失败时的结果 */ class Failure(val error: Exception) : Result()将 interface 关键字改成 sealed class,由于密封类是一个可继承的类,因此在继承它的时候需要在后面加上一对括号。
改写成密封类之后,getResultMsg() 函数中的 else 条件已经不需要了:
fun getResultMsg(result: Result) = when (result) { is Success -> result.msg is Failure -> result.error.message }Q:为什么去掉了 else 条件仍然能编译通过?
A:因为在 when 语句传入一个密封类变量作为条件时,Kotlin 编译器会自动检查该密封类有哪些子类,并强制要求你将每一个子类所对应的条件全部处理。这样就可以保证即使没有编写 else 条件,也不可能出现漏写条件分支的情况。
密封类及其所有子类只能定义在同一个文件的顶层位置,不能嵌套在其他类中,这是被密封类底层的实现机制所限制的。
希望本文对你有所帮助!
上一篇: 经典问题
推荐阅读
-
SpringBoot 定时任务的两种实现方法(Scheduled和quartz)以及InitializingBean接口的作用
-
PHP使用反射机制实现查找类和方法的所在位置,php所在位置
-
实例详解简单实体类和xml文件的相互转换方法
-
java通过反射,只需要传了类名和参数,就可以根据不同参数的构造方法实例化对象
-
vue中keepAlive组件的作用和使用方法详解
-
ES6中类的静态方法有哪些作用
-
python类和函数中使用静态变量的方法
-
【转载】C#中SqlCommand类的作用以及常用方法
-
PHP动态地创建属性和方法, 对象的复制, 对象的比较,加载指定的文件,自动加载类文件,命名空间,_PHP教程
-
PHP使用反射机制实现查找类和方法的所在位置_PHP