ruby的习惯用法

Ruby有不少惯用法,这里略作一些介绍,也方便阅读他人代码:

迭代
一般写法:

for i in (1..10)
puts i
end

 



习惯写法:

Java代码 复制代码 收藏代码
  1. (1..10).each{|i| puts i}
  2. 1.upto(10){|i| puts i} # from njmzhang
(1..10).each{|i| puts i}
或
1.upto(10){|i| puts i} # from njmzhang




||=赋值
一般写法:

Java代码 复制代码 收藏代码
  1. number = 1if number.nil?
  2. number = 1 unless number
number = 1 if number.nil?
number = 1 unless number


习惯写法:

Java代码 复制代码 收藏代码
  1. number ||= 1
number ||= 1




程序入口

Java代码 复制代码 收藏代码
  1. if __FILE__ == $0
  2. if $PROGRAM_NAME == __FILE__
if __FILE__ == $0
或
if $PROGRAM_NAME == __FILE__


这个相当于main(), 逻辑判断的意思当程序名($0或另一个)和当前文件名(__FILE__)一致时,也就是当前文件是被单独执行的而不是被别的文件调用。这个方法还有个用法是作为unit test使用。


预设变量和特殊记号
类似$0的Perl风格预设常量还有很多,参见Programming Ruby p319

其中比较常用的如$:代表库搜索路径,修改方法常见有:

Java代码 复制代码 收藏代码
  1. $:.unshift('buildscript') # from gigix
  2. $: << File.join(File.dirname(__FILE__), 'CurrentClass')
$:.unshift('buildscript')  # from gigix
或
$: << File.join(File.dirname(__FILE__), 'CurrentClass') 


后一种方法使用了相对路径,因为Ruby的module不要求namespace和文件目录结构要对应一致,很多时候统统放一个目录里

%w格式化命令(from qiezi) 可以少打几个引号

Java代码 复制代码 收藏代码
  1. %w{a b c d} #等价 ['a', 'b', 'c', 'd']
%w{a b c d} #等价 ['a', 'b', 'c', 'd'] 



``(~键下的撇号)用来执行shell外部命令,如:

Java代码 复制代码 收藏代码
  1. `help`
`help`




inject
一般写法:

Java代码 复制代码 收藏代码
  1. result = []
  2. (1..10).each{|item| result << item}
result = []
(1..10).each{|item| result << item}


习惯写法:

Java代码 复制代码 收藏代码
  1. (1..10).inject([]){|array, item| array << item}
(1..10).inject([]){|array, item| array << item}


inject有点难理解,相当于python的reduce和一些FP里的fold。inject的块变量有两个(这里是array和item),第二个变量(item)用来枚举被inject的集合(这里是(1..10)这个range), 而第一个变量(array)由inject的参数初始化(这里是[],可选),并在block被反复执行时保持持久(相当于静态变量),而item则在每次枚举时被更新为下一个值。我们再看一下inject的另一种通常用法就会更明白了:求和

Java代码 复制代码 收藏代码
  1. (1..10).inject{|sum, item| sum += item}
  2. 这个等于
  3. (1..10).inject(0){|sum, item| sum += item}
(1..10).inject{|sum, item| sum += item}
这个等于
(1..10).inject(0){|sum, item| sum += item}


也就是块变量sum被初始化成0然后反复迭代执行块的内容,最后返回sum


并行赋值
这个很多人都知道了,比如:

Java代码 复制代码 收藏代码
  1. a,b = 0, 1
  2. a,b = b, a # 交换a,b
a,b = 0, 1
a,b = b, a # 交换a,b


当然可以延伸出一些很诡异的变化,不提倡使用阿

还有一个用法是让函数返回“多个结果”(不是多个对象),如:

Java代码 复制代码 收藏代码
  1. def test
  2. 1,2
  3. end
  4. x, y = test #x = 1, y = 2
def test
  1,2
end
x, y = test #x = 1, y = 2	


这个njmzhang说的很对,其实函数返回的是一个array,然后再并行匹配到变量上去。(所以我对多个结果特别加了引号)
这显然是个syntax sugar,你随便用逗号分割几个变量是不会自动组成array的。

注意这种并行匹配当两遍不平衡时会造成的问题:

Java代码 复制代码 收藏代码
  1. a,b = [1,2,3] # a = 1, b = 2, 3被丢弃
  2. a,b,c = [1,2] # a = 1, b = 2, c = nil 被初始化成nil
a,b = [1,2,3] # a = 1, b = 2, 3被丢弃
a,b,c = [1,2] # a = 1, b = 2, c = nil 被初始化成nil 




*的匹配
一般来说*用于把一个array展开:

Java代码 复制代码 收藏代码
  1. a, *b = [1,2,3] #a = 1, b = [2,3]
a, *b = [1,2,3]  #a = 1, b = [2,3]


类似FP里的x:xs(haskell), x::xs(ocaml), [a | b] (erlang from 布娃娃)


rescue简单用法

Java代码 复制代码 收藏代码
  1. begin
  2. 1/0
  3. rescue
  4. puts 'wrong'
  5. end
begin
 1/0
rescue
  puts 'wrong'
end


可以简化为

Java代码 复制代码 收藏代码
  1. 1/0 rescue puts 'wrong'
1/0 rescue puts 'wrong'




命名参数的默认值
ruby有默认参数,但其实没有所谓keyword argument,而是提供一个syntax sugar用hash模拟。但是怎么像Rails的方法那样同时利用命名参数和默认参数值呢?

Java代码 复制代码 收藏代码
  1. def image(opt={})
  2. default_opt = {:height => 25, :width => 10}
  3. default_opt.merge! opt #opt中同样key的内容会覆盖default_opt中key的value
  4. end
def image(opt={})
    default_opt = {:height => 25, :width => 10}
    default_opt.merge! opt #opt中同样key的内容会覆盖default_opt中key的value
end




精细duck typing控制
duck typing的精神就是行为决定类型,而不是相反

Java代码 复制代码 收藏代码
  1. a = []
  2. #不用
  3. if a.kind_of? Array then a << 1
  4. if a.instance_of? Array then a << 1
  5. #而用
  6. if a.respond_to? :<< then a << 1
a = []
#不用
if a.kind_of? Array then a << 1
if a.instance_of? Array then a << 1
#而用
if a.respond_to? :<< then a << 1




获取metaclass
这也比较常见了,各种动态伎俩的开始

Java代码 复制代码 收藏代码
  1. sing = class << self; self; end
sing = class << self; self; end




符号转换到Proc
一般写法:

Java代码 复制代码 收藏代码
  1. (1..10).map{|item| item.succ}
(1..10).map{|item| item.succ}


习惯写法:

Java代码 复制代码 收藏代码
  1. (1..10).map(&:succ)
(1..10).map(&:succ)


map(fun(x))般的FP风格

注意这是Rails特有的,通过ActiveSupport对Symbol插入to_proc方法。
不用Rails怎么办呢?一种办法是借助Ruby Facets库(gem install facets):

Java代码 复制代码 收藏代码
  1. require 'facet/symbol/to_proc‘
require 'facet/symbol/to_proc‘



Facets库包括大量对Ruby核心类的扩展,是个有趣而又危险的大杂烩,也许我以后会另外再专门介绍一下。

猜你喜欢

转载自jy503160.iteye.com/blog/2097187