前言
一篇库存文章,感觉再不发的话马上就要发霉了
问题
之前在写代码的时候遇到个蛮有意思的编译问题,感觉可以拿出来分享一下,首先先看一段简单的代码

有个函数,代码总共就没几行,定义了一个局部变量temp,然后让这个temp在repeat函数内执行加0.3并且打印出减去0.3后的结果,看起来代码没啥问题,抛开具体的执行结果,我们来编译一下这段代码看看

很奇怪的现象发生了,居然来了个编译报错,说的是无法进行智能转换,局部变量temp被一个可变的闭包结构捕获了,这个我就不乐意了,捕获了又咋样呢,影响你啥了就给我报个错,实在没啥头绪,只好先问问Gemini它有什么办法
分析

Gemini说,kotlin编译器无法保证一个可空的可变变量在一个闭包结构内进行修改以及访问,因为在这期间可能会被其他线程或者异步回调修改为null,就算代码看起来是同步执行的,但是编译器为了防止这个潜在的安全性问题,还是会阻止编译顺利通过,所以才报错,话虽这么说,但是不得不吐槽一下,编译器你要不要这么含蓄,有错咱就标红吗,常见的一些编译器报错,都会在相关代码上有一根红线,可以在红线的位置得到对应的报错信息

类似于上面这种代码,有错误立马就能看到,而不会像我们今天举的这个智能转换的例子,必须得在编译期间才会抛出问题,如果是小项目也就算了,但是如果换成一个大项目,随便编译一下就要花个几分钟,结果包没出来,看到一堆红字,影响效率的同时心情也不美丽,吐槽完了,那么这种问题该如何解决呢?很简单
使用空安全符?

虽然加上空安全符后会有提示说这个安全符可以不加,但忽略就好
使用let函数

一个意思,就是多加一层非空的判断,这样就能阻止在闭包结构内对局部变量进行智能转换而引发的编译问题
升级kotlin版本至2.0
这个问题kotlin官方也给出了答复,有人提了一个issue,而kotlin也认定这是一个bug,最终在2.0版本已经修复了,如果条件允许,可以将项目的kotlin版本升级至2.0版本,这样这个编译问题自动就会消失

换个例子
上述例子过于简单,可能有人会觉得实际场景中不太会遇到这种问题,那么我们看看下面这段代码

这个例子就跟我遇到的问题比较相似了,首先有个类CoffeeHolder,内部有一个静态内部类InnerHolder,在InnerHolder内部只有一个挂起函数runJob,这个时候有一个函数,它接收InnerHolder作为参数,并且在内部执行了runJob操作

最后在Activity中,有个函数runHolder执行了testHolder,代码如下

有了文章前半部分的介绍,我们现在可以立马知道这段代码不会编译通过的,在闭包(协程)中对局部变量holder进行了修改也就是赋值,随后在testHoldr中访问,编译报错的地方也就是testHolder所在的一行

解决办法就如上面提到的那样,给holder添加上空安全符或者其他非空判断才行
最后
如果有谁也遇到过这种,编辑器本身不会报错,但是在编译的过程中会报错的代码,欢迎在评论区分享