【好消息】Ruby 2.5 发布了,看看新增了些啥

前言

一直以来 Ruby 都遵循着每年圣诞节必发布一个新版本的传统,当然 17 年的圣诞节也不例外,就在 12 月 25 日发布了 Ruby 2.5。通常来讲,次版本提升可以理解为语言(包括运行时)升级了一个阶段,需要重新安装,并且不同的次版本之间可以共存。

更详细的发布周期可以看这里:https://www.ruby-lang.org/en/downloads/releases

Ruby 作为一个我很喜欢使用的 Web 后端语言(当然并不是指 Ruby 只适合做 Web 后端,只是我个人主要用来做 Web 后端而已,例如本博客后端),当然必须得追新啦~那么 2.5 版本究竟带来了那些变化呢?

准备工作

首先我们要安装 Ruby 2.5 版本,包括其附带的 Gem 2.5 和其它 Gem 次版本都是独立的,就像 Python3 使用 pip3 一样。

在 launchpad 上有一个叫 Brightbox 的团队一直在几乎第一时间构建新版的 Ruby,并且无任何问题存在。我们添加它们的 ppa:

sudo add-apt-repository ppa:brightbox/ruby-ng
sudo apt-get update

使用 Ruby 不仅仅要安装 Ruby 包,还需要 ruby-dev 和 ruby-doc 包。前者是为了在编译 Native 库时候需要满足的依赖,后者是可以关联源码文档。

sudo apt install -y ruby2.5 ruby2.5-dev ruby2.5-doc

终端输入 irb2.5 看看能否正常进入交互 Shell 并简单测试是否正常。若没问题,则测试 Gem 2.5 是否正常工作,顺便安装上 bundler:

sudo gem2.5 intall bundler

注意:多个 Ruby 版本共存的环境下,建议选择好默认的 Ruby 版本(例如上一个版本 2.4 以保证稳定性),使用最新版本则在脚本 shebang 上手动声明 ruby2.5。

新特性

rescue/else/ensure 现在允许直接与 do/end 块一起使用

这是什么意思呢?就是说:异常处理再也不需要包装一层 begin/end 块了。这个非常好理解,其实就是去掉了一层多余的语法包装。

从前:

e1 = lambda do
  begin
    eval 'i = 100hello'
  rescue Exception, _
    puts "发现错误:#{$!}"
  else
    puts 'eval 函数正常执行'
  ensure
    puts '执行完毕'
  end
end

现在:

e2 = lambda do
  eval 'i = 100hello'
rescue Exception, _
  puts "发现错误:#{$!}"
else
  puts 'eval 函数正常执行'
ensure
  puts '执行完毕'
end

对比上面两段代码,会发现下面的少了两行。不过 e1.call 和 e2.call 执行结果是完全一致的。进一步观察不难看出减少的就是 begin 和 end 所占的两行了。如果你觉得仅仅是少了两个关键字包装且仅少了两行意义不大,那可能想得不太对了。如果少了一个代码块包装,就表示减少了一段缩进,这对于靠缩进的语言而言好处不言而喻,代码看起来更直观了,特别是多层代码块嵌套的时候。

使用 Struct.new 创建允许关键字参数的类

在之前,类的默认构造方法只能按位置填充参数。但是普通方法却可以靠命名参数、参数默认值等方式支持关键字参数。但是现在多了一个 Struct.new 方法可以创建一个允许关键字参数构建类对象的方式(不过不支持默认值):

# 允许使用关键字参数构建类

# 用 x,y,r 三个参数定义一个 Adder 类
Adder = Struct.new(:x, :y, :r)
# 给 Adder 类加一个 result 方法(返回 x + y 的结果)
class Adder
  def result
    self.x + self.y
  end
end
# 创建一个 Adder 对象(给关键字参数赋值)
a1 = Adder.new(x = 19, y = 1)

puts a1.result # 20

顶级常量查找不再可用

在之前假若我们访问的常量不存在,Ruby 最终便会在全局作用域的顶层对象中寻找。假设我们写了下面一段代码:

class Auth
  VERSION = 100
end

class Twitter
end

puts Twitter::Auth::VERSION

在 2.5 版本之前,这段代码会输出 100,也就是 Auth 类中的常量 VERSION 中的值。是不是很奇怪?明明我是从 Twitter 中找 Auth 常量,明显 Twitter 中并不存在 Auth 这个常量 。但是因为顶级对象查找机制导致 Twitter::Auth 会引用到顶层的 Auth 类(类同时也是对象)上,所以能访问到 Auth 中的 VERSION 常量也不奇怪了。不过之前的版本也不是什么也不顾及的,会输出警告信息:

warning: toplevel constant Auth referenced by Twitter::Auth

但毕竟这是一个可能会造成问题的场景,现在终于决定将顶级的常量查找给关掉了。所以在 2.5 版本运行这段代码会抛出 NameError 异常:

in `<top (required)>': uninitialized constant Twitter::Auth (NameError)

当然 Ruby 2.5 还有其它特性改进,目前精力有限会逐步更新出来。

性能优化

待写。

最近流行

待写。

最后

待写。