Kotlin 1.3.61:函数字面量扩展属性返回类型解析失败问题
问题原因与解决方法
咱们先来拆解你遇到的问题:核心是编译器对lambda的返回类型推断出现了自动提升,导致实际返回的是()->Any?而非你预期的()->R?。
为什么会出现类型不匹配错误?
你的扩展属性定义里,lambda的try分支返回的是不可空的R(比如Double),而catch分支返回null。Kotlin编译器会自动推导lambda的返回类型为两个分支的公共超类型:不可空R和Nothing?(null的底层类型)的公共超类型是Any?,而不是你期望的R?。
这就导致num1和num2的实际类型是Any?,而非Double?。当你用num1!!强制解包后得到的是Any类型,它并没有定义和Double的加法运算符,自然会出现「接收者类型不匹配」的错误。
从反编译的Java代码也能佐证这一点:lambda的invoke方法返回的是Object,而非泛型参数R对应的具体类型,这是泛型擦除加上类型推断提升共同作用的结果。
解决方法:显式指定返回类型
我们需要让编译器明确知道lambda的返回类型是R?,阻止它自动提升到Any?,这里有几种简洁的写法:
写法1:强制类型转换
val <R> (()->R).nothrow: (()->R?) get() = { try { invoke() } catch(ex: Throwable) { null } as R? }
写法2:显式声明局部变量类型
val <R> (()->R).nothrow: (()->R?) get() = { val result: R? = try { invoke() } catch(ex: Throwable) { null } result }
写法3:用run块指定返回类型
val <R> (()->R).nothrow: (()->R?) get() = run<R?> { try { invoke() } catch(ex: Throwable) { null } }
修改后的验证代码
val <R> (()->R).nothrow: (()->R?) get() = { try { invoke() } catch(ex: Throwable) { null } as R? } fun main() { val num1 = "42"::toDouble.nothrow() println(num1) // 输出42.0 println(num1!! + 3.14) // 输出45.14 val num2 = "english"::toDouble.nothrow() println(num2) // 输出null }
修改后,num1和num2会被正确推断为Double?,加法运算也能正常执行。
内容的提问来源于stack exchange,提问作者xinaiz
相关产品推荐
相关产品推荐

