Ruby 基础教程第4版读书笔记 2

Ruby 的基础

运算符

赋值运算符

&&=, ||=, ^=, &=, |=, <<=, >>=
+=, -=, *=, /=, %=, **=,
$stdin.lineno += 1
$stdin.lineno = $stdin.lineno + 1
  • 表达式的执行顺序是从左到右
  • 如果逻辑表达式的真假已经可以确定,则不会再判断剩余的表达式
  • 最后一个表达式的值为整体逻辑表达式的值
item = nil
if ary
  item = ary[0]
end

item = ary && ary[0]

只有在 var 为 nil 或者 false 的时候,才把 1 赋值给它。这是给变量定义默认值的常用写法。

var = var || 1

var ||= 1
  • x..yx...y 的区别是前者包含y,后者不包含y。
  • 如果数值以外的对象也实现了根据当前值生成下一个值的方法,那么通过指定范围的起点和终点就可以生成 Range 对象。
  • 在 Range 对象内部,可以使用 succ 方法根据起点值逐个生成接下来的值。具体的说,就是对 succ 方法的返回值调用 succ 方法,然后再循环,直到得到的值比终点值大时才结束。

运算符的优先级由高到低如下

::
[]
+(一元运算符) ! ~
**
-(一元运算符)
* / %
+ -
<< >>
&
| ^
> >= < <=
<=> == === != =~ !~
&&
||
?:(条件运算符)
.. ...
=(其它赋值运算符)
not
and or

Ruby 的运算符大多都是作为实例方法提供给我们使用的,除了下面的方法之外我们都可以很方便的定义或者重定义运算符,改变其原有的含义。

::, &&, ||, .., ..., ?:, not, =, and, or

定义二元运算符时,我们常把参数名定义为 other。 另外在定义方法时候,使用 self.class 可以灵活的处理继承和 Mix-in。

class Point
  attr_reader :x, :y

  def initialize(x = 0, y = 0)
    @x, @y = x, y
  end

  def inspect
    "#{@x} #{@y}"
  end

  def +(other)
    self.class.new(x + other.x, y + other.y)
  end

  def -(other)
    self.class.new(x - other.x, y - other.y)
  end
end

point0 = Point.new(3, 6)
point1 = Point.new(1, 8)

p point0 + point1

可定义的一元运算符有 +, -, ~, ! 4个。它们分别以 +@, -@, ~@, !@ 为方法名进行方法的定义。

class Point
  def +@
    dup # 返回自己的副本
  end

  def -@
    self.class.new(-x, -y) # 颠倒x, y各自的正负
  end

  def ~@
    self.class.new(-y, x) # 坐标翻转90度
  end
end

point = Point.new(3, 6)
p +point
p ~point

数组,散列中的 obj[i], obj[i] = x 这样的方法,称为下标方法。定义下标时的方法名分别为 [][]=

class Point
  def [](index)
    case index
    when 0 then x
    when 1 then y
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end

  def []=(index, val)
    case index
    when 0 then self.x = val
    when 1 then self.y = val
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end
end

point = Point.new(3, 6)
point[0]
point[1] = 2

错误处理与异常

对于可预期的错误,我们需要留意一下两点:

  • 是否破坏了输入的数据,特别是人工制作的数据。
  • 是否可以对错误的内容及原因做出相应的提示。

异常处理有以下优点:

  • 程序不需要逐个确认处理结果,也能自动检查出程序错误
  • 会同时报告发生错误的位置,便于排查错误
  • 正常处理与错误处理的程序可以分开书写,是程序便于阅
  • 不捕捉异常意味着程序出问题就会马上终止

异常处理的写法

begin
  可能会发生异常的处理
rescue => 引用异常对象的变量
  发生异常时的处理
  sleep 10
  retry
ensure
  不管是否发生异常都希望执行的处理
end
  • 即使不指定变量名,Ruby 会把异常对象赋值给变量 $!
  • ensure 中的处理,在程序跳出 begin ~ end 部分时一定会被执行。
  • resure 中使用 retry 后, begin 以下的处理会重做一遍,注意的是这样容易形成死循环。

指定需要捕捉的异常

当存在多个种类的异常,且需要按异常种类分别进行处理时,我们可以用多个 resuce 来分开处理。

begin
  可能会发生异常的处理
rescue Exception1, Exception2 => 变量
  发生异常时的处理
rescue Exception3 => 变量
  发生异常时的处理
rescue
  发生异常时的处理
end
  • Ruby 中所有的异常都是 Exception 类的子类。
  • rescue 中不指定异常类时,程序会默认捕捉 StandardError 类及其子类。
  • 我们在自定义异常时,一般先定义继承 StandardError 类的新类,在继承这个新类。

主动抛出异常

使用 raise 方法,可以使程序主动抛出异常。

  • raise message 抛出 RuntimeError 异常,并把字符串 message 设置给新生成的异常对象
  • raise 异常类 抛出指定的异常
  • raise 异常类, message
  • raiserescue 外抛出 RuntimeError 异常。在 rescue 调用时,会抛出最后一次发生的异常 $!

如果觉得我的文章对您有用,请在支付宝公益平台找个项目捐点钱。 @Victor Nov 12, 2014

奉献爱心