Ruby 为什么uniq!如果没有重复项,则返回nil
我只是从Ruby开始,我个人发现下面的内容违反了“最小惊喜原则”。也就是说,引用那个uniq!从self中删除重复的元素。如果未进行任何更改(即未找到重复项),则返回nil 有人能解释这一点吗?我觉得这完全违反直觉?这意味着,与其通过添加.uniq来编写下面的一行代码,还不如添加.uniq!为了结束第一行,我必须写以下两行:Ruby 为什么uniq!如果没有重复项,则返回nil,ruby,arrays,uniq,Ruby,Arrays,Uniq,我只是从Ruby开始,我个人发现下面的内容违反了“最小惊喜原则”。也就是说,引用那个uniq!从self中删除重复的元素。如果未进行任何更改(即未找到重复项),则返回nil 有人能解释这一点吗?我觉得这完全违反直觉?这意味着,与其通过添加.uniq来编写下面的一行代码,还不如添加.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}/)
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\u tested.uniq!”因为它可以返回零;相反,我必须编写hooks\u tested=hooks\u tested.uniq
事实上,我认为这是一个特别令人震惊的mis特性,因为这是一个众所周知的原则,即当设计一个返回数组的方法时,至少应该返回一个空数组,而不是nil您可以在第一行末尾附加
uniq
(末尾没有感叹号)
或者,如果您坚持使用uniq代码>,使用
(hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/)).uniq!
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
这是因为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
如果您需要返回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
这不是为什么的答案,而是一个解决办法
由于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
自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):
是的,我想我可以在这种情况下,POLS对Ruby有一个特定的含义:“不会让Matz(Ruby的创建者)感到惊讶。对(不正确的)用户没有用。”您试图表达的目的,同意。如果您试图做一些事情,例如测试uniq!
,这可能就是Matz的想法。;-,我同意。这是非常PHP风格的(随机的、不一致的例外情况)。所有其他情况,包括uniq
返回原始情况。当uniq
未找到重复项时,它将返回数组本身。严重的是wtf。@MikeWoodhouse用于此目的的方法应为uniq?
而不是uniq!
来自“感叹号”的返回值“像这样的方法通常是任意的,因为它们在适当的位置修改对象。这个例子的不幸之处在于它造成了一些语义混乱,如您的示例所示:if uniq!然后…实际上不是唯一的。通常,如果你使用方法的bang形式,它将是作用于特定对象的唯一方法(即,不在链中)。这部分是为了消除不明确的语句,例如hooks=hooks.uniq!。排序
或hooks.uniq!。排序代码>(在这里,您可以对同一表达式中的同一变量进行多个赋值)或对中间临时值进行赋值,例如hooks.uniq.sort代码><代码>数组.uniq
还返回nil
而不是[]
,因此您可以执行if(hooks.uniq!)
之类的操作来修改数组,并在有任何更改时执行特殊操作。您的第二个建议会导致“nil:NilClass的未定义方法`length'”如果它不包含重复项,这正是我试图引起注意的意外行为,但显然它落在了不合逻辑的——呃,聋子——earsOkay,对不起。如果第二个例子不起作用,这里还发生了其他事情。你使用的是什么版本的Ruby?
hooks = IO.read(wt_hooks_impl_file).scan(/wt_rt_00\w{2}/).tap(&:uniq!)
puts hooks.length