我有一个看起来像这样的方法:如何在添加数字时将零值视为零?
def calculate_the_thing(hsh)
hsh[:x] + hsh[:y] + hsh[:z]
end
这需要这样的事:
{:x => 5, :y => nil, :z => 2, :a => 5}
我想修补一些类,以便当+
方法得到一个零值,它将其视为零。看起来很合理。我该怎么做?
我有一个看起来像这样的方法:如何在添加数字时将零值视为零?
def calculate_the_thing(hsh)
hsh[:x] + hsh[:y] + hsh[:z]
end
这需要这样的事:
{:x => 5, :y => nil, :z => 2, :a => 5}
我想修补一些类,以便当+
方法得到一个零值,它将其视为零。看起来很合理。我该怎么做?
正如@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
作为哈希值的方法,将覆盖默认值。
你需要猴子补丁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的可怕惊喜。
几乎在所有情况下,这是一个*真的*坏主意,因为它违背了红宝石的基本假设,并可能导致难以发现的错误。应该不惜一切代价避免以这种方式修补核心类。使用[精化](http://ruby-doc.org/core/doc/syntax/refinements_rdoc.html)时,可以使用这种安全的唯一方法。 –
@HolgerJust是的,在回答 –
后加了一个注意事项,以后再研究一下。谢谢 –
nil.to_i已经强制为0.所以,通过在输入上使用to_i,默认情况下会获得所需的行为。在所有情况下将nil定义为等于0似乎相当邪恶。 – jforberg
不知道你可以做到这一点。这是一个巨大的帮助 –