1. 运算符表达式
Ruby提供了基本的运算符集,也提供了几个独特的运算符。Ruby中的许多运算符是由方法调用来实现的。例如,当执行"a*b+c"时,实际上是请求a对象执行方法*,传入的参数是b。因为任何东西都是对象,而且可以重新定义实例方法,所以可以重新定义任何基本算术方法,例如:
class Fixnum
def +(other)
old_plus(other).succ
end
end
如果用反引号"`",或者以"%x"为前缀的分界形式,括起一个字符串,默认情况下它会被当作底层操作系统的命令来执行。表达式的返回值就是该命令的标准输出,例如:
`date`
2. 赋值
赋值语句将左侧的变量或者属性设置为右侧的值,然后返回该值作为赋值表达式的结果。这意味着可以链接赋值语句,例如:
a = b = 1
定义一个可写的对象属性,只需简单地定义一个以等于号结尾的方法即可,例如:
class Test
def value=(new_value)
@value = new_value
end
end
Ruby的赋值是以并行方式执行的,所以赋值语句右边的值不受赋值语句本身的影响。在Ruby中可以用并行赋值来交换两个变量的值,例如:
a, b = b, a
当赋值语句有多于一个左值时,赋值表达式将返回由右值组成的数组。如果赋值语句的左值多于右值,那么多余的左值将被忽略。如果右值多于左值,那么额外的右值将被忽略。如果赋值语句仅有一个左值而有多个右值,那么右值将被转换成数组,然后赋值给左值。
如果最后一个左值有一个"*"前缀,那么所有多余的右值将被集合在一起,并作为一个数组赋给左值。同样,如果最后一个右值是一个数组,可以在它的前面加一个"*",它将被适当地展开成其元素的值,例如:
a, *b = [1, 2, 3]
a, b = *[1, 2]
赋值语句的左边可以含有一个由括号括起来的变量列表,Ruby视这些变量为嵌套赋值语句,在处理更高层次的赋值语句前,Ruby会提取出对应的右值,并赋值给括起来的变量,例如:
a, b, c, d = 1, [2, 3], 4
a, [b, *c], d = 1, [2, 3, 4], 5
Ruby有一个句法的快捷方式,如"a = a + 2"可以写成"a += 2",内部处理时,会将第二种形式先转换成第一种形式。
3. 布尔表达式
Ruby对真值的定义是:任何不是nil或者常量false的值都为真。Ruby支持所有的标准布尔操作符,并引入了一个新操作符defined?。仅当"and"和"&&"的两个操作数都为真时结果才为真,并且仅当第一个操作数为真时才求解第二个操作数的值。同样,如果有一个操作数为真,那么"or"和"||"的结果为真,且权当第一个操作数为假时才求解第二个操作数。"not"和"!"返回它们的操作数的相反值。
如果参数未被定义,defined?操作符返回nil,否则返回对参数的一个描述,如果参数是yield,而且有一个block和当前上下文相关联,那么defined?返回字符串yield。
Ruby对象还支持如下比较方法:==,===,<=>,=~,eql?和equal?。除了"<=>",其他方法都是在类Object中定义的,但是经常被子类重载以提供适当的语义。比如类Array重定义了"==",当两个数组对象有相同的元素个数,且对应的元素个数也都相等时,才认为它们相等。
操作符 | 含义 |
---|---|
== | 测试值相等与否。 |
=== | 用来比较case语句的目标和每个when从句的项。 |
<=> | 通用比较操作符。 |
<, <=, >=, > | 小于、小等于、大等于、大于比较操作符。 |
=~ | 正则表达式模式匹配操作符。 |
eql? | 如果接受者和参数有相同的类型和相等的值,则返回真。 |
equal? | 如果接受者和参数有相同的对象ID,则返回真。 |
"=="和"=~"都有相反的形式:"!="和"!~",不过,在Ruby读取程序的时候,会对它们进行转换。
Ruby的if表达式和其他语言的if语句类似,例如:
if condition then
statement
elsif condition then
statement
else
statement
end
如果将if语句分布到多行上,那么可以不用then关键字。使用冒号来替代then可以使代码更简洁,例如:
if condition : statment
elsif condition : statment
else statement
end
Ruby还有一个否定形式的if语句unless,例如:
unless condition
statement
else
statement
end
Ruby也支持C风格的条件表达式,例如:
new_value = condition ? true_value : false_value
4. Case表达式
Ruby的case表达式相当于多路的if,而它有两种形式。
第一种形式接近于一组连接的if语句,它列出一组条件,并执行第一个为真的条件表达式所对应的语句,例如:
case
when condition1 : statement1
when condition2 : statement2
else statement3
end
第二种形式是在case语句的顶部指定一个目标,而每个when从句列出一个或者多个比较条件,例如:
case match
when value1
statement1
when value2
statement2
when value3
exit
else
statement3
end
和if一样,case返回执行的最后一个表达式的值,而且如果表达式和条件在同一行上的话,可以用then关键字来加以区分。
case通过比较目标和when关键字后面的比较表达式来运作,这个测试通过使用"==="来完成。只要一个类为"==="提供了有意义的语义,那么该类的对象就可以在case表达式中使用。Ruby的所有类都是类Class的实例,它定义了"==="以测试参数是否为该类或其父类的一个实例,所以case可以用来测试对象到底属于哪个类。
5. 循环
只要条件为真,while循环就会执行循环体,例如:
while line = gets
end
until循环与此相反,它执行循环体直到循环条件变为真,例如:
until value > 10
value += 1
end
使用while和until做语句修饰符时,如果被修饰的语句是一个begin/end块,那么不管布尔表达式的值是什么,块内的代码至少会执行一次,例如:
puts 'Hello' while false #nothing
begin
puts 'World'
end while false #World
for在Ruby中是一个语法块,当使用for时,Ruby将把它转换成each迭代器,例如:
for i in [1, 2, 3, 4]
puts i
end
循环控制结构break、redo和next可以改变循环或者迭代的正常流程,break终止最接近的封闭循环体,然后继续执行block后面的语句,redo从循环头重新执行循环,但不重计算循环条件表达式或获得迭代中的下一个元素,next跳到本次循环的末尾,并开始下一次迭代,例如:
while line = gets
next if line =~ /^[a-z]+/
break if line =~ /^END/
redo if line =~ /^[0-9]+/
end
在Ruby 1.8中,可以传递一个值给break和next,比如可以对break设置循环的返回值。
redo语句使得一个循环重新执行当前的迭代,但是retry可以从头重新执行一个循环,例如:
for i in 1..100
retry if gets =~ /^RETRY/
end
6. 作用域
while,until和for循环没有引入新的作用域,已存在的局部变量可以在循环中使用,而循环中新创建的局部变量也可以在循环后使用。
被迭代器使用的block略有不同,这些block中创建的局部变量通常无法在block外访问。如果执行block的时候,一个局部变量已经存在且与block中的变量同名,那么block将使用此已有的局部变量,例如:
x = 1
y = 2
[1, 2, 3].eachdo |x|
y = x + 1
end
puts x #x=1
puts y #y=4
在外部作用域中变量不必有值,Ruby解释器只需看到它即可,例如:
if false
a = 1
end
3.times {|i| a = i}
puts a #a=2