我刚开始使用Ruby,我个人发现以下内容违反了“最少惊喜原则”。那就是引用the documentation,那就是uniq! “从self中删除重复的元素。如果没有进行任何更改,则返回nil(即没有找到重复项)。”
有人可以解释一下,这对我来说似乎完全违反直觉吗?这意味着,而不是通过附加.uniq来编写下面的一行代码!为了结束第一行,我不得不写下以下两行:
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks = hooks.uniq
或者我错过了什么,更好的方法?
编辑:
我明白uniq!修改其操作数。以下是我希望更好地说明的问题:
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
puts hooks.length #50
puts hooks.uniq!.length #undefined method `length' for nil:NilClass
我认为uniq的方式!作品使它完全无意义和无用。在我的情况下,我指出我可以将.uniq附加到第一行。但是后来在同一个程序中,我将元素推送到循环内的另一个数组中。然后,在循环下,我想“删除”数组,但我不敢写'hooks_tested.uniq!'因为它可以返回零;相反,我必须写hooks_tested = hooks_tested.uniq
事实上,我认为这是一个特别令人震惊的错误特征,因为它是一个众所周知的原则,当设计一个返回数组的方法时,应该总是至少返回一个空数组,而不是nil
答案 0 :(得分:10)
这是因为uniq!
修改了self
,如果uniq!
会返回一个值,您将无法知道原始对象中是否实际发生了更改。
var = %w(green green yellow)
if var.uniq!
# the array contained duplicate entries
else
# nothing changed
end
在您的代码中,您只需编写
即可hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks.uniq!
# here hooks is already changed
如果你需要返回hook的值,也许是因为它是最后一个方法语句
def method
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks.uniq
end
或其他
def method
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks.uniq!
hooks
end
答案 1 :(得分:5)
uniq!
上的感叹号表示它修改了数组而不是返回一个新数组。你应该这样做:
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).uniq
或者
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks.uniq!
puts hooks.length
答案 2 :(得分:2)
您可以将uniq
(末尾没有感叹号)附加到第一行的末尾。
或者,如果您坚持使用uniq!
,请使用
(hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)).uniq!
答案 3 :(得分:1)
这不是解决原因的答案,而是解决方法。
由于uniq
没有返回nil
,我使用uniq
并将结果分配给新变量,而不是使用bang版本
original = [1,2,3,4]
new = original.uniq
#=> new is [1,2,3,4]
#=> ... rather than nil
拥有一个新变量是一个很小的代价。如果进行检查,重复调用uniq!
和uniq
并检查nil
答案 4 :(得分:1)
从Ruby 1.9开始,Object#tap
可用:
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap do |hooks|
hooks.uniq!
end
puts hooks.length
也许更简洁(h / t @Aetherus):
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap(&:uniq!)
puts hooks.length