为什么uniq!如果没有重复则返回 nil
我刚刚开始使用 Ruby,我个人认为以下内容违反了“最少意外原则”。也就是说,引用文档,那个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
I'm just starting with Ruby and I personally find the following to be a violation of the "principle of least surprise". And that is, quoting from the documentation, that uniq! "removes duplicate elements from self. Returns nil if no changes are made (that is, no duplicates are found)."
Can anybody explain this, which seems completely counter-intuitive to me? This means that rather than being able to write one line of code below by appending .uniq! to end the first line, I instead have to write the following two lines:
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)
hooks = hooks.uniq
Or am I missing something, a better way?
EDIT:
I understand that uniq! modifies its operand. Here's the problem illustrated better I hope:
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
I contend that the way uniq! works makes it completely senseless and useless. Sure in my case as pointed out I could just append .uniq to the first line. However later in the same program I am pushing elements onto another array inside of a loop. Then, under the loop, I'd like to "de-dupe" the array, but I dare not write 'hooks_tested.uniq!' because it could return nil; instead I must write hooks_tested = hooks_tested.uniq
Indeed I contend this is a particularly egregious mis-feature in that it is a well known principle that, when devising a method that returns an array, one should always at least return an empty array, rather than nil
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这是因为
uniq!
修改了self
并且如果uniq!
返回一个值,您将无法知道更改是否实际发生在原始对象。在您的代码中,您可以简单地编写
If you need to return the value of hook 也许因为它是最后一个方法语句,只需执行即可
,否则
This is because
uniq!
modifiesself
and ifuniq!
would return a value you wouldn't be able to know whether a change actually occurred in the original object.In your code you can simply write
If you need to return the value of hook perhaps because it's the last method statement just do
or otherwise
uniq!
上的感叹号表示它修改了数组而不是返回一个新数组。你应该这样做:或者这样
The exclamation point on
uniq!
indicates that it modifies the array instead of returning a new one. You should do this:or this
从 Ruby 1.9 开始,
Object#tap
可用:也许更简洁(h/t @Aetherus):
Since Ruby 1.9,
Object#tap
is available:And perhaps more succinctly (h/t @Aetherus):
您可以将
uniq
(末尾没有感叹号)附加到第一行的末尾。或者,如果您坚持使用
uniq!
,请使用You can append
uniq
(no exclamation mark at the end) to the end of the first line.Or, if you insist on using
uniq!
, use这不是原因的答案,而是一种解决方法。
由于
uniq
不返回nil
,因此我使用uniq
并将结果分配给新变量,而不是使用 bang版本变量是一个很小的代价。它肯定比执行 if 检查要好得多,重复复杂的调用
uniq!
和uniq
并检查nil
This is not an answer to why, but rather, a workaround.
Since
uniq
doesn't returnnil
, I useuniq
and assign the the result to a new variable instead of using the bang versionHaving a new variable is a small price to pay. It sure as hell beats doing if checks, with repeated complex calls to
uniq!
anduniq
and checking fornil