说三个自己也用过的技巧,没用过的也写不出来。
空指针保护
这个非常常见。
看个例子:
a ||= []
## 上面的|| 是逻辑操作符或,相当于 a || (a = [])
上面这个方法的好处在于,它可以保证a不为nil,这种惯用方法称为空指针保护。
空指针保护常常用于初始化实例变量。比如下面的例子:
class C
def data
@data ||= {}
end
def data?
@data.present?
end
end
Tap
《ruby元编程》里面提到了tap,使用tap,可以在方法链中插入中间操作,比如:
temp = ['a','b','c'].push('d').shift
puts temp #=> a
x = temp.upcase.next
上诉的代码显得很不ruby,使用tap改进下,可以这么写:
['a','b','c'].push('d').shift.tap {|x| puts x}.upcase.next #=> a
其实tap在方法定义中也很常见。比如i18n-tasks的源代码中,就多次出现了tap的身影:
举一个简单的例子感受下:
# source是一个Array,存放文件路径
# get_all_files 可以获取指定的单个或多个路径下所有的文件
def get_all_files(source)
files = []
source.map do |path|
path = path[-1] == '/' ? path : path + '/'
group = Dir.glob("#{path}**/**")
files << group.reject { |x| File.directory?(x) }
end
end
如果换成tap,则可以这样定义:
def get_all_files(source)
[].tap do |files|
source.map do |path|
path = path[-1] == '/' ? path : path + '/'
group = Dir.glob("#{path}**/**")
files << group.reject { |x| File.directory?(x) }
end
end
end
Symbol#to_proc
这个在rubyist高手中算是比较流行的一种技巧了。
看个常用的数组求和:
a = [1,2,3,4]
a.reduce(&:+) #= > 10
a.inject(0,&:+) #= > 10
「reduce 和inject 是alias的关系, 两者可以互用。我依然记得第一次看到数组求和[1,2,3,4].reduce(&:+)
这个例子时,一脸懵逼……」
这种带有&:+
的标记的,就是Symbol#to_proc。
上面的求和,如果不用Symbol#to_proc, 则可以这样写:
a = [1,2,3,4]
a.reduce{|sum, x| sum + x } #= > 10
a.inject(0){|sum, x| sum + x } #= > 10
对于Symbol#to_proc 的方法的使用,要注意一点,那就是&:method
中的method,必须是对象可以调用的无参method,比如上面的&:+
,+ 是1,2,3,4都可以调用的无参实例方法。
看个例子感觉下:
b = ['hi','ruby','hello']
b.map(&:capitalize) #= > ["Hi", "Ruby", "Hello"]
b.map(&:nil?) #= > [false, false, false]
b.map(&:concat('world')) #= > raise: syntax error
b中的每一个元素都是String对象,可以成功调用无参的实例方法capitalize,nil?等,但是当调用带有参数的concat方法时就会报错,为什么?
原来在Symbol类中有一个to_proc方法,用于把符号转化为一个Proc对象:
class Symbol
def to_proc
Proc.new {|x| x.send(self)} # 动态派发,调用self这个method的
end
end
上面的b.map(&:capitalize)
等价于b.map(&:capitalize.to_proc)
, 由于&可以调用对象的to_proc方法把对象转为一个proc,所以可以简写成b.map(&:capitalize)
, 也就是说,b.map(&:capitalize)
等同于b.map{|x|x.send(:capitalize)}
。
注意到Symbol类中定义的to_proc方法是不带参数的。
当然,如果你想要调用带参数的method,可以自定义一个method或者考虑给to_proc打个猴子补丁。