Ruby修改freq属性时band属性被意外设为true问题排查
Ruby自定义Radio类freq赋值时band被篡改为true的问题修复
问题复现
学习Ruby面向对象编程实现Radio类时,volume属性修改逻辑运行正常,但调用freq=方法修改频率时,初始化为'fm'的@band实例属性会被错误修改为布尔值true,复现代码如下:
调用入口init.rb:
require_relative 'classes/radio' fm_radio = Radio.fm fm_radio.volume = 10 puts fm_radio.status # 输出: volume: 10 band: fm frequency: 88.0 fm_radio.freq = 99.0 puts fm_radio.status # 异常输出: volume: 10 band: true frequency: 99.0 puts fm_radio.band # 输出: true
类定义radio.rb原始代码:
class Radio attr_accessor :volume, :freq attr_reader :band def initialize(band) @band = band if band == 'am' @freq = 540.0 else @freq = 88.0 end @volume = 1 end def volume=(value) return if value < 1 || value > 10 @volume = value end def freq=(value) if @band = 'am' && (540.0..1600).include?(value) @freq = value elsif @band = 'fm' && (88.0..108.0).include?(value) @freq = value else puts 'out of range' end end def crank_it_up @volume = 11 end def status "volume: #{@volume} band: #{@band} frequency: #{@freq}" end def self.am Radio.new('am') end def self.fm Radio.new('fm') end end
问题成因
freq=方法中存在两个错误共同导致异常:
- 条件判断时误将比较运算符
==写成了赋值运算符=:原本要判断@band是否等于'am'/'fm',写成了直接给@band赋值 - Ruby运算符优先级规则中,逻辑与
&&的优先级高于赋值运算符=,所以表达式@band = 'am' && (540.0..1600).include?(value)的实际执行逻辑是:先计算'am' && 范围判断结果——非空字符串'am'本身是真值,所以整个子表达式的返回值就是后面范围判断的布尔结果(传入99.0时AM范围判断返回false,走到FM分支时范围判断返回true),最终这个布尔值被直接赋值给@band,就出现了band变成true的异常。
修复代码
将freq=方法中的赋值单等号改为比较双等号,同时给比较条件加括号明确优先级,避免优先级歧义:
def freq=(value) if @band == 'am' && (540.0..1600).include?(value) @freq = value elsif @band == 'fm' && (88.0..108.0).include?(value) @freq = value else puts 'out of range' end end
修复后重新执行测试代码,设置freq = 99.0时输出为volume: 10 band: fm frequency: 99.0,逻辑恢复正常。
内容的提问来源于stack exchange,提问作者mark howard
相关产品推荐
相关产品推荐

