Kotlin 2.1.0的新改进带来哪些改变

新改进

在 Kotlin 2.1.0 版本引入了一个新的改进:Improved overload resolution for functions with generic types

官方描述,是对泛型函数的重载解析进行了加强,例如在过去:

kotlin 复制代码
class KeyValueStore<K, V> {
    fun store(key: K, value: V) {} // 1
    fun store(key: K, lazyValue: () -> V) {} // 2
}

fun <K, V> KeyValueStore<K, V>.storeExtension(key: K, value: V) {} // 1
fun <K, V> KeyValueStore<K, V>.storeExtension(key: K, lazyValue: () -> V) {} // 2

fun test(kvs: KeyValueStore<String, Int>) {
    // Member functions
    kvs.store("", 1)    // Resolves to 1
    kvs.store("") { 1 } // Resolves to 2

    // Extension functions
    kvs.storeExtension("", 1)    // Resolves to 1
    kvs.storeExtension("") { 1 } // Doesn't resolve
}

对于类中泛型函数的重载是可以正确解析的,你传递一个lambda作为参数不会被解析到 函数1,但是在扩展函数的情况下,编译器会报错提示你存在歧义的重载函数,它无法将上边例子中的 lambda 解析到 storeExtension(key: K, lazyValue: () -> V)

在 Compose 中实现 React 的 useState?

这个问题对于我们日常开发可能影响不大,但是对于库作者而言可能有些难受。例如在 ComposeHooks 中,我一直期望实现类似 React 中 useState 的效果,即 setState 函数既能接收值,也能接收一个 (oldStateValue)=>newStateValue 函数,因为这两者在逻辑上是几乎是一致的,你只需要对 lambda 求值,就可以使用同样的逻辑来执行更新状态。

在 React 中你可以这样写:

javascript 复制代码
const [state,setState] = useState(0);

setState(1); // 更新状态值为1
setState(value => value + 1); // 更新状态值加1

这种写法非常灵活,我们经常需要使用当前状态的值进行计算,将结果作为新值赋值给状态,这是一个非常常见的场景。

这一切都是因为 JavaScript 是弱类型语言,也就是解构出的 setState 既可以接收一个函数作为参数,也可以接收一个值作为参数,但是在 Kotlin 中无法实现 Kotlin 也不支持联合类型,但是这个新特性让我看到了转机。

Arrow 前来助力

arrow 是一个非常棒的 Kotlin 函数式编程库,它扩展了 Kotlin 在函数式编程上的应用场景,在 ComposeHooks 中也有很多地方运用了这个库。

这里我们主要使用的是 Either<L,R> 这个容器类型,这个类型包装了左值与右值,其结果只能是其中之一,非常类似 Kotlin 原生的 Result 类型,它提供了方便的扩展函数 left()right() 来快速的创建 Either 实例。

回到正题,我们的 setState 函数其实是这样的一个函数:

kotlin 复制代码
typealias SetValueFn<T> = (T) -> Unit

现在它只能接收一个 值 作为参数,而不能接收一个 lambda,那如果这里的 T 的类型是这样的呢:

kotlin 复制代码
Either<T, (T) -> T>

它是一个容器类型,它的左值是值,右值是一个函数,这时我们只需要为这个函数类型的调用操作符进行重载:

kotlin 复制代码
typealias SetterEither<T> = Either<T, (T) -> T>

operator fun <T> SetValueFn<SetterEither<T>>.invoke(leftValue: T) = this(leftValue.left())

operator fun <T> SetValueFn<SetterEither<T>>.invoke(rightValue: (T) -> T) = this(rightValue.right())

然后借助 Eitherfold 函数我可以方便的处理左右值:

kotlin 复制代码
GetStateHolder(
    state = state,
    setValue = { value: SetterEither<T & Any> ->
        val newValue = value.fold({ it }, { it(state.value) }) // 处理左右值情况
        state.value = newValue
    },
    getValue = { state.value }
)

左值直接取值,右值传递当前状态的值执行 lambda 进行求值。

现在你只需 import 这个 invoke 重载,就可以获得在 React 中使用 useState 一样的体验了。

kotlin 复制代码
import xyz.junerver.compose.hooks.invoke

val (state, setState) = useGetState(default)
fun set(num:Int) {
    setState(num) // 传递值
}
fun add(){
    setState{ it +1 } // 传递函数
}

查看更多

相关推荐
希希不嘻嘻~傻希希9 分钟前
CSS 字体与文本样式笔记
开发语言·前端·javascript·css·ecmascript
alexhilton18 分钟前
MVI架构:Compose中的响应式状态管理
android·kotlin·android jetpack
石小石Orz30 分钟前
分享10个吊炸天的油猴脚本,2025最新!
前端
爷_1 小时前
Nest.js 最佳实践:异步上下文(Context)实现自动填充
前端·javascript·后端
爱上妖精的尾巴1 小时前
3-19 WPS JS宏调用工作表函数(JS 宏与工作表函数双剑合壁)学习笔记
服务器·前端·javascript·wps·js宏·jsa
草履虫建模2 小时前
Web开发全栈流程 - Spring boot +Vue 前后端分离
java·前端·vue.js·spring boot·阿里云·elementui·mybatis
—Qeyser2 小时前
让 Deepseek 写电器电费计算器(html版本)
前端·javascript·css·html·deepseek
UI设计和前端开发从业者2 小时前
从UI前端到数字孪生:构建数据驱动的智能生态系统
前端·ui
千百元4 小时前
jenkins打包问题jar问题
前端