13

我刚开始使用 Ruby,我个人认为以下内容违反了“最小意外原则”。也就是说,从文档中引用,那个 uniq! “从自身中删除重复的元素。如果没有进行任何更改(即没有找到重复项),则返回 nil。”

谁能解释一下,这对我来说似乎完全违反直觉?这意味着,而不是能够通过附加 .uniq 来编写下面的一行代码!要结束第一行,我必须编写以下两行:

  hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
  hooks = hooks.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!' 因为它可以返回 nil;相反,我必须写 hooks_tested = hooks_tested.uniq

事实上,我认为这是一个特别令人震惊的错误特征,因为这是一个众所周知的原则,即在设计返回数组的方法时,应该始终至少返回一个空数组,而不是 nil

4

5 回答 5

11

这是因为uniq!修改self和 ifuniq!将返回一个值,您将无法知道原始对象中是否实际发生了更改。

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

如果您需要返回钩子的值,可能是因为它是最后一个方法语句,只需执行

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
于 2010-01-20T15:05:15.637 回答
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
于 2010-01-20T15:04:53.233 回答
3

从 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
于 2016-09-08T00:02:49.247 回答
2

您可以将uniq(末尾没有感叹号)附加到第一行的末尾。

或者,如果您坚持使用uniq!,请使用

(hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)).uniq!
于 2010-01-20T15:04:01.003 回答
2

这不是为什么的答案,而是一种解决方法。

由于uniq不返回nil,我使用uniq并将结果分配给新变量而不是使用 bang 版本

original = [1,2,3,4]
new = original.uniq

#=> new is [1,2,3,4]
#=> ... rather than nil

拥有一个新变量是一个很小的代价。它肯定比做 if 检查要好得多,重复复杂的调用uniq!uniq检查nil

于 2016-09-07T22:18:22.367 回答