Kotlin柠檬水应用when状态切换时lemonSize值异常变化问题
问题:lemonadeState状态切换时lemonSize值异常
故障原因
这是典型的Kotlin变量作用域误用,和状态流转逻辑无关。
你在SELECT分支里写的val lemonSize = 2,是在SELECT分支的代码块内部定义了一个局部变量,这个变量的生效范围仅限当前SELECT大括号包裹的代码段,和SQUEEZE分支里访问的类层级全局lemonSize变量完全是两个独立的东西。
你在SELECT分支里给这个局部变量赋值2,等SELECT分支执行完,局部变量就会被回收,赋值根本没有同步到全局的lemonSize上。而全局lemonSize在上一轮制作流程走到DRINK状态时被设置为了-1,所以切到SQUEEZE分支读取全局变量时,拿到的自然是-1,和你预期的2不符。
你之前注释掉的val lemonSize = LemonTree()也是完全一样的错误,多写了val关键字导致重新声明了局部变量,没有修改全局状态。
修复方案
删掉SELECT分支里给lemonSize赋值语句前面的val关键字,不要新建局部变量,直接对已有的全局lemonSize赋值即可:
when (lemonadeState) { SELECT -> { Log.d(TAG, "lemonadeState at beginning of SELECT *should be SELECT* lemonadeState = $lemonadeState") // 去掉前面的val,直接给全局变量赋值,后续恢复原pick()逻辑时也不要加val lemonSize = 2 Log.d(TAG, " setting lemonSize to 2 -> lemonSize = $lemonSize") squeezeCount = 0 Log.d(TAG, " setting squeezeCount to 0 -> squeezeCount = $squeezeCount") lemonadeState = SQUEEZE Log.d(TAG, "lemonadeState at bottom of SELECT *should be SQUEEZE* lemonadeState = $lemonadeState") } SQUEEZE -> { // 原有逻辑不用改,修复后这里读到的lemonSize就会是你设置的2 Log.d(TAG, "at top of SQUEEZE *lemonSize should be 2* lemonSize = $lemonSize") Log.d(TAG, "at top of SQUEEZE *lemonadeState should be SQUEEZE* lemonadeState = $lemonadeState") squeezeCount += 1 Log.d(TAG, "decreasing lemonSize by 1") Log.d(TAG, "lemonSize before decreasing by 1 lemonSize = $lemonSize") lemonSize = lemonSize - 1 Log.d(TAG, "lemonSize after decreasing by 1 lemonSize = $lemonSize") if (lemonSize == 0) { lemonadeState = DRINK lemonSize = -1 Log.d(TAG, "lemonadeState when lemonSize == 0 lemonadeState = $lemonadeState") } } }
日志对应验证
你贴的运行日志完全可以印证这个问题:
- SELECT分支执行时打印的
setting lemonSize to 2 -> lemonSize = 2,访问的是刚声明的局部变量,所以值显示正确 - SELECT分支执行完毕后局部变量销毁,全局lemonSize仍保留上一轮结束时设置的-1,所以进入SQUEEZE分支的第一行日志就打出了
at top of SQUEEZE *lemonSize should be 2* lemonSize = -1,完全符合作用域规则的运行表现。 - 日志里的OpenGLRenderer渲染警告是模拟器通用提示,和本次业务逻辑bug无关。
内容的提问来源于stack exchange,提问作者Moya.A
相关产品推荐
相关产品推荐

