这么多年来Ruby直鲜为人知但它功能已经远远超出了最初设计时想法:以最简化思路方法操作数据和环境我第次“玩”它还是在几年前那时我正在寻找种替换处理自动管理任务批处理文件思路方法
Ruby真正开始流行还得从个来自伊利诺斯洲芝加哥市名叫37signals小公司说起它们发布了个名叫RailsWeb应用框架这个新框架吸取了已经被证明是可靠Model-View-Controller和ActiveRecord模型经验并且添加了些新思想如convention over configuration导致它实现了太多目标几乎不需要编码了
RubyCLR和IronRuby
在2006年早些时候John Lam发布了个开源项目叫做RubyCLR它在Ruby和.NET的间起到个桥梁作用它允许用户可以直接从Ruby访问.NET平台丰富资源甚至将Ruby对象都暴露给CLR了这个项目非常有雄心但它没有打算将Ruby向.NET靠拢而是打算让这两个世界相互对话你仍然需要在你机器上按照Ruby运行时环境
RubyCLR项目为人们理解如何将Ruby和.NET和谐地溶合到起迈出了关键第步John工作没有引起人们注意2006年末他在他博客上宣布加入微软新成立动态语言运行时环境(DLR)团队(Team)在John宣布前几个月微软发布了IronPython1.0版本它是Python语言在.NET框架上个新实现动态语言运行时环境在IronPython上工作它在.NET框架构建了个运行环境允许动态语言进入.NET
John和他团队(Team)在2007年MIX大会上宣布了IronRuby可能真正让人吃惊是IronRuby项目本身是微软第个真正意义上开源.NET语言不仅可以得到源代码而且还可以获取来自社区贡献
IronRuby仍然处于发展阶段然而偶然也会删掉已经可以利用东西这些东西通常是其它项目部分如最近发布Silverlight 2.0 Beta 2这些后续项目也放在源代码树中了并且也有相应邮件列表
为什么要学习Ruby?
我最喜欢本书叫做员实务:从熟练工到大师【英文名是The Pragmatic Programmer: From Journeyman to Master】该书作者鼓励员每年学习门新编程语言对于我而言当我学习了Ruby语言后大大地改变了我专业范围
Ruby是门完全面向对象语言这意味着在系统中每样打交道东西都是对象包括直接值如数字即使是类也是由新创建对象例子组成模板
Ruby是个动态语言你会发现类型已经变得不太重要了当个类以参数形式获取到个对象时不需要指定对象需要类型实际上Ruby没有编译器因此可能直到传递给类对象不满足思路方法需要时你才会发现这点
如果你象我几年前那样你也许会发现这个概念让你不安如果没有编译器那么你可能要尽可能最快地在运行前就了解代码中而不用等到运行时才知道如果你还是习惯于让编译器告诉你那你就不用选择Ruby了
正是由于以前编译器能够报告如类型不匹配当你编写个类时你可能希望“这里对象必须能够做到foo和bar”然后创建个接口叫做IFooBar看起来这是个不错解决方案但当你想使用其它在IfooBar的前创建类时(特别是那些来自框架类型)你就会失败了
作者提醒:IronRuby还没有成为主流工具你可以使用Ruby标准版本进行学习如果你想实验后面例子可以从http://rubyer.rubyforge.org/下载
Ruby举例
学习Ruby或门新编程语言最好思路方法就是多练习研究它交互接口大多数动态语言都有交互提示符称的为读-执行-打印环(即REPLRead-Execute-Pr Loop)Ruby中REPL叫做irb(即交互式Rubyeractive Ruby)
当你执行irb时你会看到个irb提示符如:
C:UsersBrad> irb
irb():001:0>
当你在irb提示符后敲入命令时Ruby解释就会评估它们并将结果输出到你屏幕上和irb类似REPL是学习门语言优秀思路方法:每次条语句下面对irb做个简单介绍在irb提示符后敲入5+2并回车告诉Ruby计算这个表达式值:
irb():001:0> 5 + 2
=> 7
irb():001:0>部分是irb提示符当你敲入5+2并回车时irb就将结果输出到屏幕上如这里=> 7=> 是irb显示输出结果时使用提示符如果Ruby认为你还没有完成表达式书写它允许你继续换行书写如当你敲入5+2+时就按了回车Ruby认为你还有部分没有输入完毕它会继续让你在下行输入如:
irb():002:0> 5 + 2 +
irb():003:0* 13
=> 20
第 2行提示符变为星号(*)了而不是“>”这样你就知道你在完成前面没有完成表达式基础类型
如果门编程语言不能处理数字那就不值得学习和使用Ruby当然能够满足算术运算了如:
irb():004:0> 3 + 4
=> 7
irb():005:0> 3 * 4
=> 12
irb():006:0> 3 - 4
=> -1
irb():007:0> 3 / 4
=> 0
irb():008:0> 3.0 / 4.0
=> 0.75
irb():009:0> 0xF
=> 15
irb():010:0> 0x3 * 0xA
=> 30
正如你所看到Ruby支持整数和浮点类型甚至可以接收常用十 6进制整数但0x3 * 0xA结果是以十进制形式显示即显示结果是30而不是0x1E
在.NET中数字也是真实对象因此你可以在它们上面类如:
irb():011:0> 14.to_s
=> "14"
在c中不要这样做
to_s类功能是将个对象转换成个串因此14.to_s返回结果是"14"和.NET中to_样to_s实际上是个对象因此在Ruby中你可以将任何东西转换成串
串
Ruby串具备完整操作支持如:
irb():012:0> "hello" + "there"
=> "hellothere"
irb():013:0> "Reader".length
=> 6
irb():014:0> "Reader".reverse
=> "redaeR"
irb():015:0> "reader".capitalize
=> "Reader"
irb():016:0> "Reader".?("foo")
=> false
irb():017:0> "Reader".?("ade")
=> true
irb():018:0> " Reader ".strip
=> "Reader"
irb():019:0> "Reader".gsub("e", "f")
=> "Rfadfr"
irb():020:0> "Reader".delete("ea")
=> "Rdr"
irb():021:0> "a" < "b"
=> true
几乎可以使用所有串操作符可能有你还从来都没有使用过如下面代码按字母顺序测试某个串是否位于其他两个的间:
irb():022:0> "Bob".between? "Adam", "Chris"
=> true
乘法操作符可以让给定串重复显示指定数量如:
irb():023:0> "hi" * 5
=> "hihihihihi"
Crypt为串提供了个单向哈希加密功能在存储敏感数据如密码时就可以使用它如:
irb():024:0> "Reader".crypt("ab")
=> "abofgDjq6JNJo"
Ruby没有内置类型它象数字样表现可以是?语法来表示个常量你可以使用chr将个数字转换成个等价串如:
irb():025:0> "Reader"[2]
=> 97
irb():026:0> ?a
=> 97
irb():027:0> 97.chr
=> "a"
赋值
其实执行这个操作并没什么用途除非你可以将其存储起来方便后面使用如:
irb():028:0>x = 42
=>42
串有个特殊语法允许嵌入式赋值这个赋值不仅仅局限于简单变量替换它是个完整赋值如:
irb():029:0> "The answer is #{x}!"
=> "The answer is 42!"
irb():030:0> "The answer is #{6 * 7}!"
=> "The answer is 42!"
可以使用单引号将串引起来避免这种赋值注意是单引号不是双引号如:
irb():031:0> 'The answer is #{x}!'
=> "The answer is #{x}!"
Ruby中和.NET 1.0中ArrayList类很接近它们大小都是可变用于存储任意类型数据从0开始编号如:
irb():032:0> a = ["hello", 42, "world"]
=> ["hello", 42, "world"]
irb():033:0> a << 5.0 * 7.5
=> ["hello", 42, "world", 37.5]
irb():034:0> a[0]
=> "hello"
irb():035:0> a[6] = 'hi' * 2
=> "hihi"
irb():036:0> a
=> ["hello", 42, "world", 37.5, nil, nil, "hihi"]
irb():037:0> a[99]
=> nil
前面代码显示了如何使用<<操作符向末尾追加项目以及获取或设置值使用指针操作符当你向末尾添加个项目时Ruby使用零值填充中“洞”当你访问外值时Ruby返回零值而不是异常
你可以使用个范围指针将分片也可以使用负指针从后向前访问-1就是最后项-2是倒数第 2项以此类推但不能使用反向范围获取反向分片你可以使用个正向范围然后reverse思路方法如:
irb():038:0> a[-1]
=> "hihi"
irb():039:0> a[1..3]
=>[42, "world", 37.5]
irb():040:0>a[2..-2]
=>["world", 37.5, nil, nil]
irb():041:0>a[-4..-1]
=>[37.5, nil, nil, "hihi"]
irb():042:0>a[-1..-4] # 不能工作
=>
irb():043:0>a[-4..-1].reverse # 能够工作
=>["hihi", nil, nil, 37.5]
和串样你会发现有多个唯对有用类如:
irb():044:0> a
=> ["hello", 42, "world", 37.5, nil, nil, "hihi"]
irb():045:0> a.compact
=> ["hello", 42, "world", 37.5, "hihi"]
irb():046:0> a.join
=> "hello42world37.5hihi"
irb():047:0> [10, 75, 6, 29].sort
=> [6, 10, 29, 75]
irb():048:0> [[1, 2, 3], [4, 5, 6]]
=> [[1, 2, 3], [4, 5, 6]]
irb():049:0> [[1, 2, 3], [4, 5, 6]].flatten
=> [1, 2, 3, 4, 5, 6]
散列
Ruby最后个核心数据结构是散列和.NET 1.0中散列表类似它是个联合它键值可以是任意类型值它们指向数据也可以是任意类型数据实际上大部分散列使用是符号作为键值
使用{}语法声明散列并且使用key => value格式声明值在散列中获取或设置值时都可以使用键值操作符如:
irb():050:0> h = {:foo=>'bar', :baz=>'bf'}
=> {:foo=>"bar", :baz=>"bf"}
irb():051:0> h[:foo]
=> "bar"
irb():052:0> h[:unknown]
=> nil
irb():053:0> h[:baz] = ""
=> ""
=> {:foo=>"bar", :baz=>""}
irb():054:0> h.entries
=> [[:foo, "bar"], [:baz, ""]]
变量
Ruby中变量和类名都是以小写字母开头可以包括字母、数字和下划线本地变量没有前缀例子变量以@开头全局变量以$开头
在使用变量前无需声明未化变量有个零值下面是几个预定义变量:
nil表示个“无”对象和.NET中null类似除了nil是个例子化NilClass类外
true和false分别是例子化TrueClass和FalseClass
在类中使用时self指向类对象例子;在个类中使用时它指是例子化类对象本身
__FILE__ 和__LINE__返回当前执行文件和那个文件中行号
符号
Ruby有个特殊类型串叫做符号串在Ruby中是可以被修改使用它们作为散列键是很慢而且有些情况是不能预测
除了它们是以冒号(:)开头外符号命名规则和变量命名规则致你不能改变符号值两个名字相同符号它们身份就样它们可以作为优秀散列键查找请求只需要比较整数值而不是和个可变长串值进行对比
类
Ruby中所有事物都是对象所有对象都是类例子为了探索类是个什么东西在它上面类:
5.
=> Fixnum
(2 ** 96).
=> Bignum
7.5.
=> Float
(1..10).
=> Range
"foo".
=> String
/^foo[a-e]$/.
=> Regexp
:foo.
=> Symbol
.
=> Array
{}.
=> Hash
块和闭包
虽然这和.NET 1.X中事件处理类似但当你想处理它们时还是必须要定义完整类来连接这些事件这就导致需要创建大量类框架需要它
.NET 2.0引入了匿名委派概念它们起作用和Ruby中块类似如:
irb():001:0> h = {:foo=>'bar', :hi=>'there'}
=> {:foo=>"bar", :hi=>"there"}
irb():002:0> h.each_key {|k| puts k}
foo
hi
=> {:foo=>"bar", :hi=>"there"}
irb():003:0> h.each {|k,v| puts "#{k}: #{v}"}
foo: bar
hi: there
=> {:foo=>"bar", :hi=>"there"}
正如你所看到Ruby中块语法是相当简洁:通常使用对大括号打开块和关闭块使用|x,y|语法标出传递给块变量
Ruby中块和闭包类似正如.NET 2.0中匿名委派这意味着它们有权访问它们封装作用域值即使那个作用域退出后也可以访问下面是个将几个值相乘闭包举例:
irb():004:0> n = [5, 6, 10]
=> [5, 6, 10]
irb():005:0> t = 1
=> 1
irb():006:0> n.each { |i| t *= i }
=> [5, 6, 10]
irb():007:0> t
=> 300
你甚至可以将引用存储在块中方便以后使用如:
irb():008:0> t = 1
=> 1
irb():009:0> f = lambda { |i| t *= i }
=> #
Ruby中定义比.NET简单多了不需要指定类型如:
irb():001:0> def greet(name)
irb():002:1> puts "Hello, #{name}!"
irb():003:1> end
=> nil
irb():004:0> greet "Reader"
Hello, Reader!
=> nil
irb():005:0> greet 42
Hello, 42!
=> nil
Ruby执行某些东西叫做“鸭式输入”:如果它走起路来像鸭子或声音也像鸭子那它定就是鸭子你不用问它“你是只鸭子吗?”你只需要将它当做鸭子对它呷呷地叫就可以了如果你渴望成为只鸭子只要你能呷呷地叫就可以加入这个party
注意greet定义时没有对对象类型做任何限制它只打印它们—Ruby中任何事物都是支持打印这得益于to_s类优点它可以将任何对象转换成串最终结果就是你可以greet它们
下面是另个例子:
irb():006:0> def pr_len(item)
irb():007:1> puts "Len = #{item.length}"
irb():008:1> end
=> nil
irb():009:0> pr_len "Reader"
Len = 6
=> nil
irb():010:0> pr_len [1, 4, 9]
Len = 3
=> nil
irb():011:0> pr_len 42
NoMethodError: und method <span ="pf">'
</span>length' for
42:Fixnum
from (irb):7:in <span ="pf">'</span>pr_len'
from (irb):11
这里pr_len做事情更多了:它了length因此传递给pr_len是length返回值可以传递个串或个它们都有对应length但是不能传递个数字没有对应数字length
为了在.NET中编写个类似你可能需要创建个IHaveLength接口作为你参数类型由于在你创建接口前类就已经创建好了所以不幸是可能你需要创建个类型转换器
最新评论