Ruby玩家名输入校验与超限退出 有无更优方案?能否用times/upto/until替换while
玩家名输入校验逻辑优化方案
原实现存在两个可以调整的问题:
- while循环的计数逻辑有偏移:首次输入空触发循环后,实际会提供4次输入机会,和预设的“最多3次尝试”的规则不匹配
- 循环退出的判断嵌在循环体内部,可读性较弱,完全可以用Ruby内置的
times/downto/until方法替代手动维护计数的while循环,简化代码
具体优化实现
1. 用times实现固定次数循环
把手动维护计数器的逻辑交给内置迭代器处理,从根源上避免计数偏移的bug:
MAX_TRIES = 3 def query_playername(display_message) puts display_message gets.chomp.strip end def exit_for_reason(reason) puts "Exiting the game for #{reason}" exit end player1name = nil MAX_TRIES.times do |try_count| # 第一次使用默认提示,后续提示剩余尝试次数 prompt = try_count.zero? ? "Enter Player 1's name:" : "Player name can not be empty, please enter valid Player1 name, #{MAX_TRIES - try_count} times left:" player1name = query_playername(prompt) # 拿到有效输入直接跳出循环,不再消耗剩余尝试次数 break unless player1name.empty? end # 循环跑完仍未拿到有效输入,直接触发退出逻辑 exit_for_reason('Exiting the game : exceeded number of tries!') if player1name.empty?
这种写法不需要手动执行timesleft -=1的计数操作,循环总执行次数完全可控,不会出现数错次数的问题
2. 用downto实现剩余次数递减提示
如果想保留原代码“提示剩余尝试次数”的交互逻辑,可以直接用整数的downto迭代替代while循环:
player1name = query_playername("Enter Player 1's name:") 3.downto(1) do |times_left| # 拿到有效输入直接跳出循环 break unless player1name.empty? player1name = query_playername("Player name can not be empty, please enter valid Player1 name, #{times_left} times left:") end exit_for_reason('Exiting the game : exceeded number of tries!') if player1name.empty?
这种写法完全贴合原有的交互流程,去掉了手动维护计数器、在循环末尾判断退出的冗余步骤,代码量缩减近一半
3. 用until循环收敛判断条件
如果不想纠结具体的迭代计数,也可以用until把“拿到有效输入”作为循环终止条件,把所有退出规则直接放到循环头部,提升可读性:
player1name = "" times_left = 3 until !player1name.empty? || times_left.zero? prompt = times_left < 3 ? "Player name can not be empty, please enter valid Player1 name, #{times_left} times left:" : "Enter Player 1's name:" player1name = query_playername(prompt) # 仅当输入无效时才扣减剩余次数 times_left -= 1 if player1name.empty? end exit_for_reason('Exiting the game : exceeded number of tries!') if player1name.empty?
这种写法把两个循环终止条件(拿到有效玩家名/次数耗尽)直接放在循环入口,读代码时不需要翻到循环末尾找退出逻辑,逻辑边界更清晰
内容的提问来源于stack exchange,提问作者user10309405
相关产品推荐
相关产品推荐

