Ruby 掉到 Array 链式调用的坑里了

reyesyang · 2013年05月23日 · 最后由 zw963 回复于 2013年05月28日 · 3951 次阅读

今天代码里面写了个数组链式调用,大意如下:

a = [1, 1, 2, 3, 4]
a.uniq!.reject!{|i| i % 2 == 0}    #=> [1,3]

然后就掉坑里了。如下:

a = [1, 2, 3]
a.uniq!.reject!{|i| i % 2 == 0}    #=>NoMethodError: undefined method `reject!' for nil:NilClass

查了文档才发现 uniq! 会在数组没有重复元素时直接返回 nil。

reject! { |item| block } → ary or nil reject! → Enumerator Equivalent to #delete_if, deleting elements from self for which the block evaluates to > true, but returns nil if no changes were made.

想当然为了简化代码写了链式调用,看来以后使用前得好好读读官方文档了。

我上次也掉在 reject! 里了 还是尽可能少在函数链当中用!方法吧 真的有什么性能提升吗?

#1 楼 @iBachue 性能提升不清楚,初衷只是想简化些代码

函数式写法都不用加叹号的。。因为就是为了获取返回值啊

#3 楼 @hooopo 想当然以为 a = a.uniq.reject{...}a.uniq!.reject!{...} 是等价的

这些不能称之为坑吧...熟读 doc...

这个不是链式调用的坑,而是!的坑,不光是 uniq,还包括 strip! 和 chomp!,都是一样的。 这个吃过一次亏就知道了

等 lazy 来就好了。。

#5 楼 @zj0713001 是自己坑自己...

最后一个 ! 就行了。

好吧.. 还是 = 一发吧。

#8 楼 @reyesyang 那还真是个坑 哈哈 不过经常是在函数后面加个 to_a to_s to_h 防止未知的 nil...

#6 楼 @ZombieCoder 有理,reject! 也是一样的,关键还是没使用的要读文档确定一下,不能太想当然,尤其这种比较隐性的。

#9 楼 @Saito 还是 = 直观,有安全感

别加叹号呀……额 直接用等于吧……

don't abuse the bang methods

这个不是链式调用的坑,是 api 设计的坑,这里设计的很不好

2.1.0dev :001 > [].uniq
 => [] 
2.1.0dev :002 > [].uniq!
 => nil 

(补充:看了一下,集合操作都是这个路子,可能有原因,我结论下早了点,谁来解释一下这么设计的目的)

#15 楼 @fsword 感叹号方法的返回值一般都是:是否修改了状态

#16 楼 @hooopo #17 楼 @luikore 果然就是这个原因,hooopo 的例子不是很贴切,举个有 bang 的例子

if names.compact!
  flash[:notice] = "名字有重复,已自动去重"
end

bang 方法可以用来区分状态是否变更,如果是链式调用,一般只关心变化结果,所以该用普通方法

#16 楼 @hooopo 这样解释确实更能帮助理解

#15 楼 @fsword

加 ! 标志的方法,是期望对 self 执行某个操作 (而非返回一个新的值), 因此你需要直到方法是否执行成功?当然还有另一种功用,就是相对来说执行 危险操作 的方法,也会加 ! 结尾。

! 的迭代器方法,我觉得只应该用于条件判断或循环中...

需要 登录 后方可回复, 如果你还没有账号请 注册新账号