Ruby中奇怪的实例变量故障

时间:2013-07-24 18:53:36

标签: ruby

看看这个 (用较少的草率编码编辑)

class Numeric
    @@currencies = {'dollar' => 1, 'yen' => 0.013, 'euro' => 1.292, 'rupee' => 0.019}
    attr_writer :previous_currency
    def method_missing(method_id)
        singular_currency = method_id.to_s.gsub( /s$/, '')
        if @@currencies.has_key?(singular_currency)
            @previous_currency = singular_currency
            self * @@currencies[singular_currency]
        else
            super
        end
    end

    def in(currency)
        singular_currency = currency.to_s.gsub( /s$/, '')
        rate = @@currencies[singular_currency]
        if @@currencies[@previous_currency] < rate
            self / rate
        else
            self * rate
        end
    end
end

Numeric类的扩展允许执行以下操作:

<Number>.<currency>.in(:<other_currency>)

喜欢5.dollars.in(:euros)

如果我有dollars作为我的第一个缺失方法,它就可以了。 @previous_currency在第一次拍摄时获得值dollar,然后在调用缺失的方法in时,它会保留其值并完成转换。但是,如果我尝试其他任何内容而不是dollarsdollar@previous_currency会以某种方式失去其价值,在nil的调用下再次成为in,从而导致跟随错误

NoMethodError: undefined method ` for nil:NilClass

我试图在@@currencies哈希中切换美元的位置,但同样的行为再次发生。

Ruby是否更喜欢美元?

1 个答案:

答案 0 :(得分:1)

问题是你试图在一个数字上保持状态,然后返回一些完全不同的数字。

使用美元,5.dollars会返回5,因为您天真地认为“1”的确意味着“1美元”,(那么为什么即使使用1.dollar也是如此1.in(:euros)?),因此5的@previous_currency dollar5.dollars会返回同一个对象5,并附加您附加的额外状态。

使用euros5.euros会返回6.46,这是一个完全不同的对象。它与对象5不共享任何状态,因此尚未设置@previous_currency

为了完成这项工作,您需要停止维护状态,并始终以美元返回结果,方式与5.weeks5.months和{{ 1}}返回几秒钟。然后你有一个简单的无状态数字。您还应该停止依赖5.years,并动态定义方法。这是一个简单的工作版本:

method_missing