和我一样许多习惯了java的程序员在刚刚开始接触ruby的时候对ruby当中的方法声名以及调用的方式会感到非常的奇怪和别扭。比如我们在ruby当中经常可以看到类似的方法声名 method(arg1, *args), 又如这样的方法 method2(arg2, &block), 等等。相比于java那明确简单的方法声名方式,ruby中的方法声名要灵活许多,下面就ruby当中常见的几种方法声名的形式,以及方法调用的方式做一个简要的总结:
1. 首先,不同于java的方法声名,ruby中的方法可以接收的参数是可变的,而不是像java那样必须和方法声名中的参数类型相等,个数相等。当你希望ruby方法接收一个或者多个参数的时候,可在普通的参数名前放置一个星号(*),比如:
def varargs(arg1, *rest)
“Received #{arg1} and #{rest.join(’, ‘)}”
end
varargs("one") #=>"Received one and "
varargs("one","two") #=>"Received one and two"
varargs("one","two","three") #=>"Received one and two, three"
以上代码出自《programming ruby 中文版》p80
在这里,varargs方法的第二个形参前有一个星号,表示将方法中第二个以后的所有参数都装到一个数组当中,然后赋值给rest. 所以当方法声名的参数前边又一个*的时候,代表:将方法调用时传入的所有除之前已匹配完毕的参数外的剩余参数放入一个Array并将其赋值给*后边的形参。
2. 我们也经常会见到在方法声名的参数当中有“&args”的形式,比如
class TaxCalculator
def initialize(name,&block)
@name,@block = name, block
end
def get_tax(amount)
"#{@name} on #{amount} [...]
本文是发布在该地址的screencast 的一个简要的总结
在该视频当中,作者 Tom Wermer和大家一起分享了一些ruby/rails特有的语法格式,从中可以体会都ruby/rails的强大便捷的功能, 共有9个例子,每一个例子都对应一个传统的冗长的语法格式(sucky)和更简便版本的语法格式(awesome),从而可以使你进行对比:
1. 一般用在给变量赋默认值的时候,如果为nil,则将其赋一值
# Super Sucky
if not breakfast
breakfast = :bacon
end
# Sucky
breakfast = :bacon unless breakfast
# awesome
breakfast ||= :bacon
2.简化判断的方法,
# sucky
if val == 1 || val ==12 || val == 42
puts "bacon"
end
#awesome
if [1,12,42].include?(val)
puts "bacon"
end
3. 当我们有这种需求,即:如果array当中没有某个元素就向其中添加,的时候以下用法能够简化代码
fruits = ["apple","banana"]
# sucky
#如果fruits当中不存在"apple",将苹果添加到fruits
fruits +=["apple"] unless fruits.include?("apple")
#=> ["apple","banana"]
#awesome
fruits |= ["apple"]
#=> ["apple","banana"]
4. 这个技巧也非常的使用,我们在之前写代码的过程当中也经常的使用,就是用constant variable来替换代码当中的 string, integer等常量
#sucky
class [...]
今天在看beast源代码,在看到topics_controller # show的时候发现了一行读不懂的代码:
@voices = @posts.map(&:user) ;
然后看了看doc,发现doc上并没有关于这种用法的解释,于是google,也没有找到合适的答案,无奈,只能自己尝试。通过puts @voices 我发现@voices是一个user 对象的集合,而post belongs_to user, 到这里我并没有找到任何的关联;这时我又试着将&:user替换为&:user_id,这时候再puts @voices,打印出来的是数字,。。。嗯似乎有点明白了;再将&:user_id替换成&:body,put出来的是string array body的值。这下终于明白了,原来 @posts.map(&:user)==@posts.map{|post| post.user}