《搜索引擎零距离》第三章 IRS虚拟机及编译器实现原理(2)

[b]3.1.4 类和方法的定义[/b]
1. 类定义
例子:
class Foo < Super
def test
:
end
:
end

语法:
class 标识符 [< superclass ]
表达式 ..
end
该语法用来定义类的内容。类名是以大写字母开头的标识符。
类定义实际上就是把类赋值给由类名指定的常数(在 Ruby 中,类也是一个对象,它是 Class 类的实例)。
若某个类已经被定义过,此时又用相同的类名进行类定义的话,就意味着对原有的类的定义进行追加。例子:
class Foo < Array
def foo
end
end

class Foo
def bar
end
end
在类定义表达式中,self 指的是该类本身,这与顶层没有什么不同。可以在类定义表达式中写入任何表达式,在定义类时这些表达式将被执行。
类定义中可以出现嵌套。例子:
class Foo
class Bar
end
end
上面的例子中,嵌套外侧的 Foo 类和内侧的 Bar 类之间没有继承关系之类的功能上的联系(除了常数 Bar 是 Foo 中的常数 Foo:Bar 之外)。类的嵌套就是指,把与类有关的类/模块放在该类的外侧,使它们构成一个整体,借以表达某种包含关系。类定义表达式将返回最后被计算的表达式的值。若最后的表达式不返回值,就返回 nil。
2. 模块定义
例子:
module Foo
def test
:
end
:
end
语法:
module 标识符
表达式 ..
end
该语法用来定义模块的内容。模块名是以大写字母开头的标识符。模块定义实际上就是把模块赋值给由模块名指定的常数(在 Ruby 中,模块也是一个对象,它是 Module 类的实例)。若某个模块已经被定义过,此时又用相同的模块名来定义模块的话,就意味着对原有的模块定义进行追加。模块定义表达式将返回最后被计算的表达式的值。若该表达式不返回值,则返回 nil。
[b]3. 方法定义[/b]
例子:
def fact(n)
if n == 1 then
1
else
n * fact(n-1)
end
end
语法:
def 方法名 [( [arg [=default]] ... [, * arg] )]
表达式 ..
[rescue [error_type,..] [then]
表达式 ..]..
[ensure
表达式 ..]
end
在定义语句所在的区域内定义一个方法。也就是说,若在类/模块的定义部分定义一个方法的话,该方法就属于这个类/模块。若在顶层定义了一个方法的话,您就可以在任何地方调用它。这种方法其实就是其他语言中所说的“函数”。方法名中,除了可以使用通常的标识符以外,还可以使用可重定义的运算符(例如 ==、+、- 等。请参考运算符表达式)。
若给临时参数指定了默认表达式的话,在方法调用过程中如果实参被省略时,该默认表达式的值就会变成默认值(调用方法时,在方法定义内计算默认表达式的值)。若最后一个临时参数的前面带*的话,所有剩下的实参数将被转为数组后传递给该参数。
例子:
# 没有参数的方法。以下省略 end
def foo
end

# 有参数的方法
def foo(arg, arg2)

# 有默认参数的方法
def foo(arg = nil)

# 参数一应俱全
def foo(arg, arg2, arg3 = nil, *rest)

# 运算符表达式
def ==(other)
def +(other)
def *(other)
在方法定义中,只能以下列顺序指定临时参数。其中任何一项都是可选的。
 没有默认表达式的参数(可多选)
 有默认表达式的参数(可多选)
 带 * 的参数(只能有一个)
为了捕捉在方法运行时发生的异常,可以使用同 begin 一样的rescue、ensure 语句。方法定义表达式返回 nil。
[b]4. 方法计算[/b]
调用方法时,将按照下列顺序计算各个表达式。
 参数的默认表达式(若有的话)
 方法的内容
 根据发生异常的实际状况,处理方法定义表达式的rescue部分或else部分(如果有的话)
 ensure 部分(如果有的话)
在方法内,根据实际情况来计算这些部分,包括参数的默认表达式在内。方法的返回值就是传给 return 的值。若没有调用 return 时,将返回在 ensure 部分之前最后计算的式子的值。调用未定义的方法会引发 NameError 异常。
[b]5. 特殊方法定义[/b]
例子:
def foo.test
print "this is foo\n"
end
语法:
def 表达式 .标识符 [( [ 参数 [= default]] ... [,* 参数 ])]
表达式 ..
[rescue [error_type,..] [then]
表达式 ..]..
[else
表达式 ..]
[ensure
表达式 ..]
end
特殊方法就是专属于某个对象的方法。特殊方法的定义可以嵌套。类的特殊方法将被该类的子类所继承。换言之,类的特殊方法所起的作用,与其他面向对象系统中的类方法的作用是相同的。特殊方法定义表达式返回 nil。
[b]6. 类方法的定义[/b]
Ruby 中的类方法是指类的特殊方法。在 Ruby 中,类也是对象。因此,若能在类对象中定义方法的话,该方法就会成为类方法。具体的定义方法如下(模块也一样):
class Hoge
def Hoge.foo
end
end

# 在类定义的外侧也行
def Hoge.bar
end

# 若使用下面的方法来定义,即使类名改变了,也不必更改方法定义
class Hoge
def self.baz
end
end
[b]7. 与定义有关的操作 alias[/b]
例子:
alias foo bar
alias :foo :bar
语法:
alias 新方法名 旧方法名
该语法给方法或全局变量添加别名。可以给方法名指定一个标识符或 Symbol。 alias 表达式返回 nil。
[b]3.1.5 运算符表达式[/b]
例子:
1+2*3/4
为了便于编程,有些方法调用和控制结构是以运算符的形式出现的。Ruby 语言中有下列运算符:
高 ::
[]
**
-(单项) +(单项) ! ~
* / %
+ -
<< >>
&
| ^
> >= < <=
<=> == === != =~ !~
&&
||
.. ...
?:(条件运算符)
=(+=, -= ... )
not
低 and or
左侧的“高”和“低”表示运算符的优先级。例如&&的优先级要高于||,如下所示:
a && b || c # => (a && b) || c
a || b && c # => a || (b && c)
大部分运算符都是特殊形式的方法调用,但有些运算符被嵌入在语言之中,无法进行重定义。能够重定义的运算符(方法)包括:

| ^ & <=> == === =~ > >= < <= << >>
+ - * / % ** ~ +@ -@ [] []= `
+@、-@ 表示单项运算符 +、-,在方法定义等场合中可以使用这种表示法。由多个运算符组合而成的自运算运算符、“!=”以及“!~”是不能重定义的。
不能重定义的运算符包括:
= ?: .. ... ! not && and || or ::
1. 赋值运算符=
例子:
foo = bar
foo[0] = bar
foo.bar = baz
语法:
变量 '=' 表达式
常量 '=' 表达式
表达式 '['表达式..']' '=' 表达式
表达式 '.' 标识符 '=' 表达式
我们使用赋值表达式向变量等对象进行赋值。赋值表达式也可以用作局部变量和常数的声明。赋值表达式的左边必须是下列表达式之一:
(1) 变量
变量 '=' 表达式
若左边是变量的话,就将表达式的结果代入其中。
(2) 数组调用
表达式1 '[' 表达式2 ... ']' '=' 表达式n
先计算表达式 1 得到一个对象,再把从表达式 2 到表达式 n 作为参数,来调用该对象的“[]=”方法。
class C
def initialize
@ary = [0,1,2,3,4,5,6,7]
end
def [](i)
@ary[i * 2]
end
def []=( i, v )
@ary[i * 2] = v
end
end
c = C.new
p c[3] # 变成 c.[]( 3 ), 结果为6
p c[3] = 1 # 变成 c.[]=(3,1),结果为1
(3) 属性调用
表达式1 '.' 标识符 '=' 表达式2
先计算表达式1得到一个对象,再以表达式2作为参数来调用该对象的“标识符=”方法。
class C
def foo
@foo
end
def foo=( v )
@foo = v
end
end
c = C.new
c.foo = 5 # 变成 c.foo=( 5 )
p c.foo # => 5
还可以使用 attr_accessor 来定义属性。
class C
attr_accessor :foo
end
c = C.new
c.foo = 5 # 变成 c.foo=( 5 )
p c.foo # => 5
(4) 自运算
例子:
foo += 12 # foo = foo + 12
foo *= 3 # foo = foo * 3
语法:
表达式1 op= 表达式2 # 表达式 1 等同于普通赋值表达式左边的部分
其中,op 为下列运算符中的某一个。运算符与=之间不留间隔。
+, -, *, /, %, **, &, |, ^, <<, >>, &&, ||
这种赋值形式和
表达式1 = 表达式1 op 表达式2
等同。
(5) 多重赋值
例子:
foo, bar, baz = 1, 2, 3
foo, = list()
foo, *rest = list2()
语法:
表达式 [',' [ 表达式 ',' ... ] ['*' [ 表达式 ]]] = 表达式 [, 表达式 ... ]['*' 表达式 ]
'*' [ 表达式 ] = 表达式 [, 表达式 ... ]['*' 表达式 ]
多重赋值是指,在多个表达式以及数组中同时进行的赋值。左边的各个表达式必须是可以被赋值的。若右边只有一个表达式,则将该表达式的结果转为数组后,再把数组中的各单元依次赋值给左边。若右边数组单元的数量超过左边的话,将忽略多余的数组单元。若右边数组单元个数不足,则将向左边多余的单元中代入 nil。
若左边最后一个表达式前带*,则将右边多余的单元以数组的形式代入这个带*的表达式中。若右边没有多余的单元,就把空数组代入其中。
例子:
foo, bar = [1, 2] # foo = 1; bar = 2
foo, bar = 1, 2 # foo = 1; bar = 2
foo, bar = 1 # foo = 1; bar = nil
foo, bar = 1, 2, 3 # foo = 1; bar = 2
foo = 1, 2, 3 # foo = [1, 2, 3]
*foo = 1, 2, 3 # foo = [1, 2, 3]
foo, *bar = 1, 2, 3 # foo = 1; bar = [2, 3]
[b]2. and运算符[/b]
例子:
test && set
test and set
语法:
表达式 && 表达式
表达式 and 表达式
首先计算左边的表达式,若结果为真就接着计算右边的表达式。and 运算符的作用与&&相同但优先度更低。将包含 and 的表达式作为某方法的参数时,必须使用双层括号。
[b]3. or运算符[/b]
例子:
demo || die
demo or die
语法:
表达式 '||' 表达式
表达式 or 表达式
首先计算左边的表达式,若结果为假就接着计算右边的表达式。or 运算符的作用与||相同但优先度更低。将包含 or 的表达式作为某方法的参数时,必须使用双层括号。
[b]4. not 运算符[/b]
例子:
! me
not me
i != you
语法:
'!' 表达式
not 表达式
若表达式值为真就返回假,若表达式值为假则返回真。也可以使用下面的语法。
表达式 '!=' 表达式 # 等同于 !(表达式 == 表达式)
表达式 '=~' 表达式 # 等同于 !(表达式 =~ 表达式)

[b]5. 条件运算符[/b]
例子:
obj == 1 ? foo : bar
语法:
表达式1 ? 表达式2 : 表达式3
根据表达式 1 的结果,选择返回表达式 2 或表达式 3的值。它与
if 表达式1 then 表达式2 else 表达式3 end
完全相同。
[b]3.1.6 变量和常量[/b]
Ruby 变量和常量的种类包括全局变量、实变量、局部变量和常量,它们都是根据其名称的第一个字符来区分的。通常,变量名称第二个字符开始是使用字母、数字或_。内部变量的名称中有一部分是$+ 1个符号的变量(详细介绍请参考内部变量)。
1. 全局变量
例子:
$foobar
以$开头的变量就是全局变量,程序的任何地方都能引用(因此应用时要特别注意)。全局变量没有必要事先声明。引用尚未初始化的全局变量其值为 nil。
2. 实变量
例子:
@foobar
以@开头的变量就是实变量,它属于特定的对象。实变量可以在其类或子类的方法中引用。实变量的默认值为 nil。
3. 局部变量
例子:
foobar
以小写字母或“_”开头的标识符就是局部变量或方法调用。在局部变量作用域(类、模块和定义方法的部分)中以小写字母开头的标识符要进行初始赋值,这个赋值属于局部变量的声明。
4. 常量
例子:
FOOBAR
以大写字母开头的标识符就是常量。常量的定义和初始化就是进行代入赋值,但是在方法里是不能定义的。访问未定义的常量会发生 NameError 异常。
常量可在类/模块中定义,除在该类/模块中可以引用外,该类的子类或嵌套该模块的类/模块中也能引用该常量。从外部引用常量要用到::运算符。而且,类和模块的名称也要和常量同时使用。
class Foo
FOO = 'FOO'
end

class Bar < Foo
p FOO # => "FOO"
end

p Foo::FOO # => "FOO"
类和嵌套外侧存在同名常数时,会先引用嵌套外侧的常数。也就是说,引用常数时会先搜索嵌套关系的外侧,然后才会按照继承关系向上搜索。而顶层常数定义并不是位于嵌套外侧,所以在搜索了继承关系之后才能找到它。可见顶层常数的优先级很低。
5. 伪变量
在普通变量以外,还有一种被称为伪变量的特殊变量。
(1) self
变量self是指当前方法的执行对象本身。
(2) nil
nil是NilClass 类唯一的实例,表示假。
(3) true
tre是TrueClass 类唯一的实例,表示真。
(4) false
FalseClass 类唯一的实例。表示伪。
不能更改伪变量的值。为伪变量代入赋值会出现语法错误。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值