Smalltalk块闭包内能否使用whileTrue:?循环逻辑不生效排查
块内嵌套
whileTrue:的语法合法性 这种写法完全受Smalltalk语法支持,不存在任何语法规则禁止在to:do:的遍历块内部嵌套使用whileTrue:循环,这是Smalltalk开发中组合控制流的常规用法。
你遇到的循环未按预期重复执行、直接跳转至外层迭代的问题,全部来自实现层面的疏漏,和语法限制没有关系。
常见的实现疏漏场景
结合你实现光线投影的步进逻辑,以下几类问题是触发当前异常表现的最高发原因:
- 对
whileTrue:的执行机制理解偏差
Smalltalk中whileTrue:的接收者是一个无参、返回布尔值的块,执行时会在每一次循环迭代前重新求值这个块,只有块返回值为true时才会执行后续的循环体块。
很多人写的时候会提前把条件算成一个固定值传进去,比如先写isOpen := (map at: x at: y) = 0,再拿这个变量当whileTrue:的接收者,这种写法等价于循环只判断一次初始状态,根本不会跟着坐标更新重新判断:如果初始位置是墙,循环根本一次都跑不起来;如果初始位置是空地,又会陷入死循环。正确的写法是把条件本身写成块,每次迭代重新计算坐标对应的单元格状态。 - 步进变量的作用域错误
光线步进依赖的坐标累加变量(currentX/currentY)如果没有声明在whileTrue的条件块、循环体块的公共可见作用域中,会出现变量遮蔽的问题:循环体内部修改的只是块内的局部变量副本,条件块读取的永远是初始的坐标值,一旦条件首次判断为false就直接退出。 - 非本地返回触发的上下文中断
Smalltalk的块支持非本地返回逻辑:如果在嵌套的块内部直接使用^语句返回,会直接从最外层的方法上下文中断执行,表现上和“直接跳转到外层do:块的下一次迭代”高度相似,但实际上如果触发这类逻辑,整个外层的60次视角遍历会直接终止,而非正常完成后续迭代。可以加断点检查循环体内部是不是意外写了提前返回的逻辑。 - 坐标越界异常被静默捕获
当光线步进的累加坐标超出5×5地图的索引范围时,调用map at: x at: y会触发索引越界异常,如果运行环境开启了异常静默拦截,当前执行上下文会被直接中断,呈现的效果和循环主动退出完全一致。
符合执行预期的嵌套写法参考
| map totalViews currentX currentY stepX stepY stepRadians hitHeight | "初始化5x5自定义地图" map := Matrix rows: 5 columns: 5 contents: #( 1 1 1 1 1 1 0 0 0 1 1 0 1 0 1 1 0 0 0 1 1 1 1 1 1 ). totalViews := 60. 1 to: totalViews do: [ :angleIndex | "计算当前视角的步进方向" stepRadians := angleIndex / totalViews * Float pi * 2. stepX := stepRadians cos * 0.1. stepY := stepRadians sin * 0.1. "初始化光线起点为地图中心" currentX := 3. currentY := 3. "条件块逐次求值,校验坐标范围、单元格状态" [ (currentX between: 1 and: 5) and: [ (currentY between: 1 and: 5) and: [ (map at: currentX rounded at: currentY rounded) = 0 ] ] ] whileTrue: [ "步进更新坐标" currentX := currentX + stepX. currentY := currentY + stepY. ]. "计算命中后的投影高度" hitHeight := 100 / (currentX squared + currentY squared sqrt max: 0.1). ].
内容的提问来源于stack exchange,提问作者Guinness
相关产品推荐
相关产品推荐

