Kotlin中AutoCloseable实现类调用use函数报错解决方案
你的判断完全正确,报错的核心原因就是Kotlin标准库默认的kotlin.io.use扩展仅约束接收者实现java.io.Closeable接口,而你的CommandChannel实现的是更通用的java.lang.AutoCloseable接口,类型不匹配导致use函数无法调用,后续的it未解析、return不合法等报错都是这个根因引发的连锁错误。
不需要编写额外的适配器类,两种极简方案即可实现安全的资源自动关闭:
方案1:直接使用标准库内置的AutoCloseable版本use扩展
Kotlin 1.2及以上版本已经在kotlin.streams包下提供了适配AutoCloseable的use扩展,只需要替换导入即可,同时可以简化lambda内的返回逻辑,避免非局部return的编译错误:// 注意导入这个包的use,不要导入kotlin.io下的Closeable专用版本 import kotlin.streams.use fun isReady(): Boolean { return getCommandChannel().use { cc -> try { cc.writeMessage("blahblah") // 直接把判断结果作为lambda返回值,不需要裸return cc.readMessage().error == null } catch (e: ChannelConnectionException) { false } } }这个实现和你写匿名函数版本的逻辑完全一致,但更简洁,资源会在代码块执行结束(无论正常返回还是抛出异常)时自动调用close,不会出现连接泄漏。
方案2:自定义通用的AutoCloseable use扩展
如果你的项目使用的Kotlin版本低于1.2,或者不想依赖streams包的扩展,自己实现一个通用扩展函数即可,逻辑和标准库实现完全对齐:inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R { var thrown: Throwable? = null try { return block(this) } catch (e: Throwable) { thrown = e throw e } finally { try { close() } catch (closeE: Throwable) { thrown?.addSuppressed(closeE) ?: throw closeE } } }把这段代码放到项目的公共工具类位置,之后所有实现AutoCloseable的资源都可以直接调use实现自动关闭,和Closeable的use用法完全一致。
你最初lambda版本里的'return' is not allowed here报错,是因为无标签的裸return在lambda中属于非局部返回,会直接跳出外层函数,虽然在这个场景下逻辑看似可行,但Kotlin默认不允许在这类上下文里使用无标签return,直接把判断结果作为lambda最后一行的返回值即可规避这个问题,不需要特意改用匿名函数传参。
内容的提问来源于stack exchange,提问作者Quuxplusone

