641 字
3 分钟
浅谈Kotlin中的泛型和类型转换
起因
由于我的项目分割开了common模块和其他子模块, 子模块需要使用common相同的代码, 但是提供的类型又不是统一的, 所以就引入了泛型 (generics)这个概念
刚开始学Kotlin的时候觉得泛型很难, 但是现在看起来泛型其实还挺好理解的(但是协变和逆变还是没理解, 因为没有用到)
泛型和类型转换的对比
泛型的本质是类型擦除(Type Erasure)。这意味着,在编译时,泛型类型会被擦除为其原始类型。例如, List<Int> 和 List<String> 在运行时都变成了 List 类型。
而类型转换是通过as操作符来显式的进行转换, as操作的时候需要进行类型检查, 这会消耗一小部分资源
(微乎其微)但是体现在大项目中就不是这么回事了
代码部分
假设我们需要一个命令执行拦截器, 拦截器的函数就需要传入匹配到的命令以及触发命令的消息 而消息又细分为
Group和Private分别代表群聊和私聊消息, 既然是在common模块中 那么这三种类型就不存在, 因为这三种类型只存在于子模块中, 所以需要在common模块中 定义三个接口分别代表这三种类型, 然后让子模块中的具体类型实现这三个接口。
在定义泛型的时候可以指定类型约束
interface IExecutionInterceptor<B : IBaseCommand, G : IGroupMessage, P : IPrivateMessage> {
/**
* 在群组命令执行之前执行, 可以返回[CommandResult]中的枚举类
* 来确定是否继续执行这条命令
* @param command 触发拦截器的命令
*/
suspend fun beforeGroupExecute(message: G, command: B): CommandResult {
return CommandResult.CONTINUE
}
/**
* 群组命令执行之后要执行的代码片段
* @param command 触发拦截器的命令
*/
suspend fun afterGroupExecute(message: G, command: B) {}
/**
* 在私聊命令执行之前执行, 可以返回[CommandResult]中的枚举类
* 来确定是否继续执行这条命令
* @param command 触发拦截器的命令
*/
suspend fun beforePrivateExecute(message: P, command: B): CommandResult {
return CommandResult.CONTINUE
}
/**
* 私聊命令执行之后要执行的代码片段
* @param command 触发拦截器的命令
*/
suspend fun afterPrivateExecute(message: P, command: B) {}
}子模块中的impl
/**
* 实现了拦截器
*/
abstract class ExecutionInterceptor : IExecutionInterceptor<BaseCommand, GroupMessage, PrivateMessage>这里指定了具体的类型, 用户只要继承这个抽象类就能重写
IExecutionInterceptor中的公开方法