Kotlin中子类与Mono的类型不匹配:为何需强制转换?
在Kotlin开发中遇到如下类型不匹配错误:
错误:
Type mismatch. Required: Mono<Authentication> Found: Mono<CustomAuth!>
触发错误的代码:
fun example(): Mono<Authentication> { return Mono.just("") .map { _ -> CustomAuth() } .onErrorReturn(CustomAuth()) }
其中Authentication来自org.springframework.security.core,CustomAuth定义如下:
class CustomAuth : Authentication { // ... }
添加强制转换后代码可正常运行:
fun example(): Mono<Authentication> { return Mono.just("") .map { _ -> CustomAuth() as Authentication } .onErrorReturn(CustomAuth()) }
疑问:为何需要添加该强制转换?
这是Kotlin泛型的不变性,加上Reactor操作符的类型推导规则共同造成的:
Kotlin泛型默认不变
和Java不同,Kotlin的泛型默认是不变的——哪怕CustomAuth是Authentication的子类,Mono<CustomAuth>也不能直接当成Mono<Authentication>用。Java里可以用通配符Mono<? extends Authentication>处理这种子类泛型场景,但Kotlin的类型推导不会自动完成这个向上转型。Reactor的类型推导限制
map操作符会根据lambda的返回值自动推导后续Mono的泛型类型。当你返回CustomAuth()时,Kotlin会把map后的Mono类型定为Mono<CustomAuth>,而不是自动提升为父类的Mono<Authentication>,这就导致了返回类型不匹配的错误。强制转换的作用
添加as Authentication后,相当于显式告诉Kotlin:该lambda的返回值类型是Authentication而非CustomAuth。此时map操作符会推导出Mono<Authentication>,刚好匹配函数的返回类型。而onErrorReturn里的CustomAuth()没问题,因为这里是直接给Mono<Authentication>传错误返回值,Kotlin会自动将其向上转型为Authentication,无需额外处理。
另外还有更优雅的替代写法,无需强制转换,直接给map显式指定泛型类型即可:
fun example(): Mono<Authentication> { return Mono.just("") .map<Authentication> { _ -> CustomAuth() } .onErrorReturn(CustomAuth()) }
通过声明map要转换的目标泛型类型,让Kotlin自动完成向上转型,代码更规范。
内容的提问来源于stack exchange,提问作者A Jar of Clay

