找回密码
 注册
搜索
热搜: java php web
查看: 589|回复: 7

(笔记)关于学习Ruby的一些总结--Ruby习惯用法

[复制链接]
发表于 2009-1-26 19:54:42 | 显示全部楼层 |阅读模式
(笔记)关于学习Ruby的一些总结--Ruby习惯用法
前一段学习Ruby过程中,总结了一些一些习惯用法及功能,希望跟大家一些讨论
Ruby有不少惯用法,这里略作一些介绍,也方便阅读他人代码:
迭代
一般写法:
代码
1.        for i in (1..10)   
2.            puts i   
3.        end  
习惯写法:
代码
1.        (1..10).each{|i| puts i}   
2.        或   
3.        1.upto(10){|i| puts i} # from njmzhang   
||=赋值
一般写法:
代码
1.        number = 1 if number.nil?   
2.        number = 1 unless number  

习惯写法:
代码
1.        number ||= 1  

程序入口
代码
1.        if __FILE__ == $0  
2.        或   
3.        if $PROGRAM_NAME == __FILE__  

这个相当于main(), 逻辑判断的意思当程序名($0或另一个)和当前文件名(__FILE__)一致时,也就是当前文件是被单独执行的而不是被别的文件调用。这个方法还有个用法是作为unit test使用。
预设变量和特殊记号
类似$0的Perl风格预设常量还有很多,参见Programming Ruby p319
其中比较常用的如$:代表库搜索路径,修改方法常见有:
代码
1.        $:.unshift('buildscript')  # from gigix   
2.        或   
3.        $: << File.join(File.dirname(__FILE__), 'CurrentClass')   

后一种方法使用了相对路径,因为Ruby的module不要求namespace和文件目录结构要对应一致,很多时候统统放一个目录里
%w格式化命令(from qiezi) 可以少打几个引号
代码
1.        %w{a b c d} #等价 ['a', 'b', 'c', 'd']   
``(~键下的撇号)用来执行shell外部命令,如:
代码
1.        `help`  
inject
一般写法:
代码
1.        result = []   
2.        (1..10).each{|item| result << item}  

习惯写法:
代码
1.        (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的另一种通常用法就会更明白了:求和
代码
1.        (1..10).inject{|sum, item| sum += item}   
2.        这个等于   
3.        (1..10).inject(0){|sum, item| sum += item}  

也就是块变量sum被初始化成0然后反复迭代执行块的内容,最后返回sum
并行赋值
这个很多人都知道了,比如:
代码
1.        a,b = 0, 1  
2.        a,b = b, a # 交换a,b  

当然可以延伸出一些很诡异的变化,不提倡使用阿
还有一个用法是让函数返回“多个结果”(不是多个对象),如:
代码
1.        def test   
2.          1,2  
3.        end   
4.        x, y = test #x = 1, y = 2     

这个njmzhang说的很对,其实函数返回的是一个array,然后再并行匹配到变量上去。(所以我对多个结果特别加了引号)
这显然是个syntax sugar,你随便用逗号分割几个变量是不会自动组成array的。
注意这种并行匹配当两遍不平衡时会造成的问题:
代码
1.        a,b = [1,2,3] # a = 1, b = 2, 3被丢弃   
2.        a,b,c = [1,2] # a = 1, b = 2, c = nil 被初始化成nil   
*的匹配
一般来说*用于把一个array展开:
代码
1.        a, *b = [1,2,3]  #a = 1, b = [2,3]  

类似FP里的x:xs(haskell), x::xs(ocaml), [a | b] (erlang from 布娃娃)
rescue简单用法
代码
1.        begin   
2.         1/0  
3.        rescue   
4.          puts 'wrong'   
5.        end  

可以简化为
代码
1.        1/0 rescue puts 'wrong'  
命名参数的默认值
ruby有默认参数,但其实没有所谓keyword argument,而是提供一个syntax sugar用hash模拟。但是怎么像Rails的方法那样同时利用命名参数和默认参数值呢?
代码
1.        def image(opt={})   
2.            default_opt = {:height => 25, :width => 10}   
3.            default_opt.merge! opt #opt中同样key的内容会覆盖default_opt中key的value   
4.        end  
精细duck typing控制
duck typing的精神就是行为决定类型,而不是相反
代码
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  
获取metaclass
这也比较常见了,各种动态伎俩的开始
代码
1.        sing = class << self; self; end  
符号转换到Proc
一般写法:
代码
1.        (1..10).map{|item| item.succ}  

习惯写法:
代码
1.        (1..10).map(&:succ)  

map(fun(x))般的FP风格
注意这是Rails特有的,通过ActiveSupport对Symbol插入to_proc方法。
不用Rails怎么办呢?一种办法是借助Ruby Facets库(gem install facets):
代码
1.        require 'facet/symbol/to_proc‘  
Facets库包括大量对Ruby核心类的扩展,是个有趣而又危险的大杂烩,希望以后能跟大家一下交流一下。--
发表于 2009-1-26 20:53:27 | 显示全部楼层
mark 一下先,ruby 这一词出现的频率越来越高,也许哪天也会被卷入ruby的大潮中,先为自己找些资源总不是错

thanks
and
回复

使用道具 举报

发表于 2009-1-26 20:54:49 | 显示全部楼层
cool ruby cool world
回复

使用道具 举报

发表于 2009-1-26 22:22:34 | 显示全部楼层
,支持支持!
回复

使用道具 举报

发表于 2009-1-26 21:32:28 | 显示全部楼层
回复

使用道具 举报

发表于 2009-1-26 22:20:21 | 显示全部楼层
很好. 向喜欢这种习惯.
回复

使用道具 举报

发表于 2009-1-26 22:07:03 | 显示全部楼层
学习ing...
回复

使用道具 举报

发表于 2009-1-26 22:18:32 | 显示全部楼层
写得好。不过还是难记。真要用到的时候就想不起来了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|软晨网(RuanChen.com)

GMT+8, 2024-9-20 17:29

Powered by Discuz! X3.5

Copyright © 2001-2023 Tencent Cloud.

快速回复 返回顶部 返回列表