Ruby 2.0发布 新特性介绍

开发 开发工具
Ruby2.0目前已经发布了,各位Ruby的粉丝们是否已经体验过了?本文将介绍最新的Ruby2.0的一些新特性,到底有哪些变化呢,请详细阅读下文。

本月24日(也就是明天)Ruby 2.0终于就要发布了。

Ruby核心团队的卜部昌平桑昨天在一个内部学习会上的presentation,介绍了Ruby 2.0所包含的一些新特性。

(本文内容选译自该幻灯片。)

为什么有Ruby 2.0?

  • 因为我们在改变事物。

  • 我们渴望让自己变得越来越快乐、健康、以及高产。

  • 不必畏惧。“拥抱变化。”

Ruby 2.0有什么新鲜的?

什么不是Ruby 2中的新鲜货

  • 几乎所有的东西。

  • “100%后向兼容”,matz如是说。

    • 在现实中……
  • (举个例子来说)Rails仍然能完好运行如初。

也就是说,

  • 新的东西被加进来了。

  • 许多内部的东西得到了改进。

Ruby 2.0的新句法

关键字参数(Keyword arguments)

下面的代码在1.x中能够正常工作:

 
  1. obj.method "with":lots => "of",  
  2.                    :args => "in",  
  3.                    :hash => "form" 

但是,问题出在哪呢?

问题是在定义该方法的时候: (Mort注:在Ruby 1.x中,只能将多个带符号名称的参数作为一个Hash来传递给方法。要为参数指定默认值,实现起来就很累赘,参见如下代码)

 
  1. def obj.method(arg, hash)  
  2.   lots = Hash[:lots] || "default" 
  3.   args = Hash[:args] || "another" 
  4.   hand = Hash[:by hand] || "annoying" 
  5.   ...  
  6. end 

注意到代码中错误的Hash[:by hand]——手写代码是错误产生的根源!

从2.0开始,Ruby将引入关键字参数:

 
  1. def obj.method(a, b = 1, c: 1, d: 2) 

其中a为固定参数,b为可选参数,c、d则为关键字参数。这样,局部变量a、b、c和d都将被恰当地赋值。

在调用函数时,原有的调用方式无需更改。

Mort注:虽然幻灯片里没有写,传统的基于Hash参数的调用方法是这个样子的

 
  1. obj.method("foo":c => 2, :d => 3) 

现在Ruby 2.0同时也支持直接采用关键字参数的调用方法:(Python程序员一定会觉得这种语法更亲切)

 
  1. obj.method("foo", c: 2, d: 3) 

更详细的示例,可以参考这里:

http://brainspec.com/blog/2012/10/08/keyword-arguments-ruby-2-0/

其他细微的句法改进

  • 引入了符号数组字面值%i和%I。

 

  1. %i(foo bar baz) # => [:foo, :bar, :baz] 

 

  • Ruby现在默认把所有的输入都视作UTF-8编码。当然你也可以显式地指定需要的编码。

Ruby 2.0的核心性能改进

require的改进

  • 背景:今天,由于我们有了许多gems,启动Ruby有时甚至需要一次require 128+个库——这带来了糟糕的性能问题。

  • 解决:require变得更快了(从计算复杂度的意义上来说)。

    • 若干技术被应用于减少多余的计算上。

Backtrace惰性生成

  • 起初,backtraces只是字符串数组而已。

  • 每当抛出异常时,这些字符串就被自上而下地生成出来,即使在它们没有实际用途的情况下。

    • 这导致了超乎寻常的低效,尤其是当你有1024+个stack frames时(这在Rails应用中很常见)。
  • 从Ruby 2.x开始,Thread::Backtrace被用来取代字符串。

    • 它们非常地轻量级。
  • 当你需要查看backtrace时,只需将它们转换成字符串即可(调用#to_s)。

Flonum类

  • 在64位平台(如今早就烂大街了)上,指针,整型和浮点型数均是64位宽度的。

  • 在Ruby中,指针和整型均为C级别的register寄存器变量。而double却是存储在内存中的,如果我们能够如操作指针一样操作它们,将如何呢?

  • 问题:如何让一个指针和一个double共存于一个union中?

  • 解决:一些技巧性的位移。

Mort注:图片懒得搬运了……请参见原幻灯片。

GC(Garbage Collection)

  • Bitmap标志:以前,GC标志位存储于每个对象中,但现在已经被转移到了专用的内存页中,以减少缓存的误查询(同时也更加CoW (Copy-on-Write)友好)。

  • 非递归标志:标志函数如今避免了机器栈溢出的风险。

  • 惰性清理(从1.9.3起):清理器只有在必须的地方才进行收集(减少了stop时间)。

Ruby 2.0的新核心特性:#1 调试工具

DTrace支持

TracePoint支持

GC stats

Ruby 2.0的新核心特性:#2 核心库

细粒度的异步中断处理

Ruby的执行有时会因为各种原因而中断,例如,超时。

Ruby 2.0提供了细粒度的异步中断处理方案:

 

  1. Thread.async_interrupt_timing Timeout::Error => :defer do 
  2.   timeout(rand()) do 
  3.     begin 
  4.       Thread.async_interrupt_timing Timeout::Error => :immediate do 
  5.         setup  
  6.         handle  
  7.         ...  
  8.       end 
  9.     ensure 
  10.       teardown  
  11.     end 
  12.   end 
  13. end 

 

模块前插

有时候你想要给一个方法添加需要的安装或拆解代码,而相应的部分却定义在别处。

 

  1. module ActiveRecordHelper  
  2.   def save  
  3.     ???  
  4.   end 
  5. end 

 

该如何去做呢?在Ruby 2.0中,你可以:

 

  1. class Foo < AR::Base  
  2.   prepend AR::Helper  
  3.  
  4.   def save  
  5.     bar  
  6.   end 
  7. end 
  8.  
  9. module AR::Helper  
  10.   def save  
  11.     foo  
  12.     super 
  13.     baz  
  14.   end 
  15. end 
  16.  
  17. Foo.new.save  

 

这避开了Rails中的所谓“别名方法链(alias method chain)”的困扰。AMC什么的已经不再必要了。

惰性枚举器

Ruby的foo.bar.baz. ...风格(所谓的“流水作业”)有时会传递许多并不必要的临时对象,而这些理论上都可以通过惰性求值来避免。

 

  1. File.open(path) {|fp|  
  2.     fp.each_line. \  
  3.     select {|line| # 生成了临时数组  
  4.     /regexp/ =~ line  
  5.     }. \  
  6.     each_with_index.map {|line, no| # 生成了临时数组  
  7.     sprintf("%d: %s\n", no, line)  
  8.     }. \  
  9.     first(10).each {|str| # 生成了临时数组  
  10.         puts(str)  
  11.     }  

 

 

  1. File.open(path) {|fp|  
  2.     fp.each_line.lazy \  
  3.     select {|line| # 没有临时数组产生  
  4.     /regexp/ =~ line  
  5.     }. \  
  6.     each_with_index.map {|line, no| # 没有临时数组产生  
  7.     sprintf("%d: %s\n", no, line)  
  8.     }. \  
  9.     first(10).each {|str| # 没有临时数组产生  
  10.         puts(str)  
  11.     }  
  12. # 甚至在到达EOF之前都不读取数据 

 

一个有趣的应用实例:无穷枚举器。

 

  1. # Leibniz formula for π  
  2. (0..Float::INFINITY).lazy.map {|i|  
  3.     ((-1) ** i) / (2*i + 1).to_f  
  4. }.take(65536).reduce(:+) * 4 

 

其他的新方法

  • Kernel.__dir__:获取__FILE__所在的目录名。
  • Kernel#to_h:通用的Hash转换方法。
  • Random类(1.9+):可重复的PRNG。
  • IO#wait_writable:等待直到可写。
  • Refinements: 实验性的。

Mort注:更多关于Ruby 2.0核心特性的介绍,参考

Ruby 2.0标准库的改进

  • CGI
    • CGI已经为HTML5做好了一切准备。
  • net/http
    • 支持SNI(Server Name Indication)。
  • Zlib绑定
    • Zlib如今运行在解释器的进程锁之外。这意味着zlib在多线程的情形下运行速度将更快。
  • 更新的stdlibs(标准库)
    • Rubygems 2.0.0
    • JSON 1.7.7
    • Rake 0.9.5
    • Rdoc 4.0
    • 以及其它(REXML,yaml,openssl……)

总结

什么不是Ruby 2中的新鲜货

  • 几乎所有的东西!

  • “100%后向兼容”,matz如是说。

  • (举个例子来说)Rails仍然能完好运行如初。

  • 不必畏惧!开始使用2.0.0版吧!

也就是说,

  • 新的东西被加进来了。

  • 许多内部的东西得到了改进。

  • 即使你对你当前的环境充分自信,2.0.0仍然值得你拥有。

Don’t be afraid. Use Ruby today!

视频:AKB48 - Ruby

原文链接:http://www.soimort.org/posts/140/

责任编辑:林师授 来源: Mort Yao的博客
相关推荐

2019-03-05 10:27:53

Linux 系统 数据

2009-06-16 11:25:57

phpMyAdmin

2012-08-13 10:40:37

Ubuntu Twea操作系统

2013-02-25 14:02:07

RubyWeb

2013-05-28 09:49:04

Hadoop 2.0大数据数据存储

2011-10-14 06:58:30

Ubuntu 11.1特性

2011-10-28 10:21:57

Ruby

2009-03-30 09:16:16

JBossSOAEclipse

2009-04-01 08:53:34

JavaRebelJVM插件

2012-03-14 12:29:55

JavaPlay Framwo

2014-09-12 10:46:35

Java9

2012-02-16 09:15:48

JavaJActor

2011-10-10 09:56:43

Ruby

2009-07-21 12:49:10

Ruby on RaiRoR

2011-07-07 10:33:27

Ruby

2011-07-13 15:09:48

PHP

2011-10-28 14:23:46

Ruby

2009-09-04 16:21:37

Ruby on Rai

2009-11-30 13:43:49

Rails 2.3Ruby 1.9

2011-03-30 14:29:13

QuartzJava
点赞
收藏

51CTO技术栈公众号