2016-02-06 118 views
2

我有一个看起来像这样的方法:如何在添加数字时将零值视为零?

def calculate_the_thing(hsh) 
    hsh[:x] + hsh[:y] + hsh[:z] 
end 

这需要这样的事:

{:x => 5, :y => nil, :z => 2, :a => 5} 

我想修补一些类,以便当+方法得到一个零值,它将其视为零。看起来很合理。我该怎么做?

+5

nil.to_i已经强制为0.所以,通过在输入上使用to_i,默认情况下会获得所需的行为。在所有情况下将nil定义为等于0似乎相当邪恶。 – jforberg

+0

不知道你可以做到这一点。这是一个巨大的帮助 –

回答

6

正如@jforberg所指出的那样,您可以使用#to_i方法,该方法将为0返回零。

def calculate_the_thing(hsh) 
    hsh[:x].to_i + hsh[:y].to_i + hsh[:z].to_i 
end 

另外,您还可以使用自动默认值来定义散...

hsh = Hash.new{0} 

但是,如果你有一个明确提出nil作为哈希值的方法,将覆盖默认值。

4

你需要猴子补丁Nilclass强制nil为一个整数。下面是代码:

class NilClass 
    def coerce(n) 
    return [0, n] if n.is_a? Numeric 
    super 
    end 
end 

1 + nil 
#=> 1 

看一看这个线程 - In Ruby, how does coerce() actually work? - 了解coerce概念。


然而,与上面的代码中的一个问题:

nil + 1 
#=> undefined method `+' for nil:NilClass (NoMethodError) 

要解决这个问题,你将不得不在NilClass

class NilClass 
    def +(param) 
    param + self 
    end 
end 

nil + 1 
#=> 1 

定义+方法,如果我们尝试冒险尝试:

nil * 10 
#=> undefined method `*' for nil:NilClass (NoMethodError) 

通过冒险,让我们通过执行我们自己的method_missing处理程序来处理所有这样的undefined method

class NilClass 
    def method_missing m, *args, &block 
    args.first.send(m, self, &block) if args.size == 1 
    end 
end 

p nil * 1 
#=> 0 

接下来,让我们尝试:

nil + "hello" 
# '+': can't convert NilClass to String (NilClass#to_str gives NilClass) (TypeError) 

让我们解决这个问题以及

class NilClass 
    def to_str 
    "" 
    end 
end 

nil + "hello" 
#=> "hello" 

接下来,让我们试试这个:

nil + [1,2,3] 
#=> '+': can't convert NilClass to Array (NilClass#to_ary gives NilClass) (TypeError) 

让我们解决它:

class NilClass 
    def to_ary 
    [] 
    end 
end 

nil + [1,2,3] 
#=> [1, 2, 3] 

我们现在有这个版本的NilClass

class NilClass 
    def coerce(n) 
    return [0, n] if n.is_a? Numeric 
    super 
    end 

    def method_missing m, *args, &block 
    args.first.send(m, self, &block) if args.size == 1 
    end 

    def to_str 
    "" 
    end 

    def to_ary 
    [] 
    end 
end 

注意::上面的代码显示您要什么可以做到。但是,这应该仅用于实验和学习目的。在所有操作中使nil表现得像其他操作数一样是不可行的,并且您最终会以无限制的方式修补NilClass。 因此,最好避免使用这种猴子修补程序,以避免未来将维护您的代码的Rubyists的可怕惊喜。

+2

几乎在所有情况下,这是一个*真的*坏主意,因为它违背了红宝石的基本假设,并可能导致难以发现的错误。应该不惜一切代价避免以这种方式修补核心类。使用[精化](http://ruby-doc.org/core/doc/syntax/refinements_rdoc.html)时,可以使用这种安全的唯一方法。 –

+0

@HolgerJust是的,在回答 –

+0

后加了一个注意事项,以后再研究一下。谢谢 –