【KTips】在Kotlin中实现一个十分简单的自循环状态机

在平日的编码生活中,你有没有遇到过需要通过状态机来实现的逻辑呢?一个状态的轮转、事件订阅的通讯处理等。

状态机的实现方式千变万化,这里我会为你介绍一个简单的自循环状态机实现。

简单介绍

在开始之前,我先说明一下这个所谓的 "自循环状态机" ,避免歧义。这个词儿是我自己编出来的,

意为这个状态机中的 动作变换 均由状态本身来完成。

用大家都喜欢的大白话来讲,就是 "状态" 是一个 class,它自己包括了它的 "行为" ------ 也就是一个可执行方法,

然后这个方法的返回值便是下一个将被 "变换""状态"

文字表述还是缺乏力量,接下来便用代码来为你展示。

实现

类型定义

让我们来定义状态机中不断轮转的状态

Kotlin 复制代码
public abstract class State<S : State<S>> {
    
    /**
     * 行为.
     * @return 下一个状态,或结束循环。 
     */
    public abstract operator fun invoke(): S?
}

那么最基础的抽象定义便结束了。很简单不是吗?

!info

根据业务需求,invoke 也可以适当地调整,比如让它变为 suspend 可挂起的。

自循环扩展

定义完了非常简单的状态 类型 State,接下来就是实现它的 "自循环"。
State 的自循环其实很简单:提供一个初始状态,然后不断地循环,

invoke 的结果来代替当前的状态,直到循环结束。

但是在每一个使用状态机的地方都去写这么一些逻辑还是会有些啰嗦,

此时扩展函数便派上了用场。

我们先来看代码:

Kotlin 复制代码
public suspend inline fun <S : State<S>> S.loop(
    onEach: (S) -> Boolean = { true },
    onNext: (S?) -> S? = { it }
): S {
    var state = this // 1
    while (onEach(state)) { // 2
        state().let(onNext)?.also { state = it } ?: return state // 3
    }

    return state
}

在上面的代码中,我们在 1 处定义了初始的状态,也就是 loopreceiver 参数 S

并从 2 处开始进入循环,也就是开始了我们状态的"自循环"。

每一次循环我们都会执行当前状态 state 的行为逻辑 invoke,并将它的返回结果设置为当前状态,

如此循环往复,直到循环终止,或者行为逻辑 invoke 返回了 null,并最终向 loop 返回最后一个被执行的状态。

除了状态本身,自循环扩展函数 loop 提供了两个用来干涉循环流程的函数 onEachonNext 来使得 loop 更加灵活,

而得益于 Kotlin 的内联函数,它们几乎不会带来什么副作用。

简单用法

纸上得来终觉浅,我们用一个简单的例子来看看这个状态机是如何使用的。

我们假设有一个订阅事件的逻辑如下:
获取10次 开始 接收事件 结束

那么用代码来实现的话大概就可以是这个样子:

Kotlin 复制代码
fun main() {
    Start.loop()
}

/** 三个状态的统一类型 */
sealed class MyState : State<MyState>()

/** 代表开始。 */
data object Start : MyState() {
    override fun invoke(): MyState {
        // 进入 '接收事件' 阶段,此处假设给它分配了一个id
        return Receive(Random.nextLong())
    }
}

/** 代表接收事件。有一个计数器,到达10后结束 */
data class Receive(val id: Long) : MyState() {
    var times = 0
    override fun invoke(): MyState {
        // 达到10次以上,结束此状态循环,进入结束状态
        if (times >= 10) {
            return Done
        }
        println("times = $times")

        // 递增计数,并返回自身,也就是继续保持 Receive 状态
        times++
        return this
    }
}

/** 代表结束。 */
data object Done : MyState() {
    override fun invoke(): MyState? {
        // 结束状态可以再做一些什么操作,然后返回 null 终止循环
        println("Done!")
        return null
    }
}

结尾

以上就是一个简单的自循环状态机的实现啦!怎么样,是不是很简单呢?

如果有帮助到你,我的荣幸~

相关推荐
papership2 分钟前
【C++类的基本概念与定义】
开发语言·c++
计算机学姐2 分钟前
基于Python的在线考试系统【2026最新】
开发语言·vue.js·后端·python·mysql·django·flask
武子康4 分钟前
Java-190 EVCache入门:Netflix 级分布式缓存架构、性能指标与多区域部署全解析
java·redis·分布式·缓存·架构·guava·guava cache
曾几何时`5 分钟前
字符串(七)409. 构造出来的最长回文串
java·前端·javascript
SadSunset18 分钟前
(9)基于xml的自动装配
java·笔记·spring
hhcgchpspk20 分钟前
linux查找并杀死进程部分方法
linux·运维·服务器·网络·经验分享
森诺Alyson20 分钟前
前沿技术借鉴研讨-2025.12.9(胎儿面部异常检测/超声标准平面检测/宫内生长受限)
论文阅读·人工智能·经验分享·深度学习·论文笔记
董世昌4123 分钟前
JavaScript 变量声明终极指南:var/let/const 深度解析(2025 版)
java·服务器·前端
hetao173383723 分钟前
2025-12-10 hetao1733837的刷题笔记
c++·笔记·算法
aini_lovee24 分钟前
直接序列扩频(DSSS)通信系统MATLAB仿真指南
开发语言·matlab