Showing posts with label Ruby的语法结构. Show all posts
Showing posts with label Ruby的语法结构. Show all posts

Monday, October 13, 2008

(10)Ruby的运行机制

Ruby是一个脚本语言,这意味着Ruby程序是一些列可执行的脚本。缺省情况下这些脚本是顺序执行的,除非遇到条件判断语句,则脚本可以根据不同的条件跳转或者循环执行。
使用过类似C或者Java这类语言的程序员都知道,代码必须编译后才能执行,Ruby不需要编译,它可以直接执行脚本程序。在Java或者C语言中都有一个main 函数作为程序的“入口”,程序会从main还是开始执行,而Ruby不是,它是从代码的第一行开始顺序执行,其实这样说也不准确,准确的说Ruby会先从头扫描整个文件,然后从第一行开始顺序执行。Ruby程序通过一个简单的命令行执行,比如:ruby test.rb
实际上只有当Ruby遇到下面这些情况才会停止执行:
  • 执行到一个结束标记。
  • 已经到达文件结尾。
  • 执行到__END__关键字。

(9)Ruby中的程序编码

Ruby的底层是一些列的字符,Ruby采用了ASCII字符集,在默认情况下Ruby认为你的编码也是ASCII,当然你也可以指定字符集,比如通过ruby -k 开关,在Ruby1.9中你可以在代码的第一行(如果有shebang,就在第二行)增加下面的注释告诉Ruby解析器,你用的编码是什么
#coding:utf-8
程序编码实际上还区分源代码编码和运行时编码,这两个是不同的,Ruby1.9中还提供了额外的-E开关来制定字符编码:



ruby -E utf-8 # -E 为字符编码的名称
ruby -Eutf-8 # 空格是可选的
ruby --encoding utf-8 # --encoding 后为编码的名称
ruby --encoding=utf-8 # 或者你可以用等号

Sunday, October 12, 2008

(8)Ruby中的文件结构

只有很少的规则规定一个ruby文件应该如何组织。
  1. 如果一个Ruby文件要包含一个shebang注释告诉类Unix操作系统该如何执行这个文件,那么这个注释必须位于文件的第一行。
  2. 如果Ruby文件要包含文档性注释(可以通过rdoc查看),那么这个注释必须位于第一行,或者如果存在shebang那么它必须位于第二行。
  3. 如果Ruby文件中包含一个前后都空白的__END__关键字,那么这个关键字后面的所有内容都会被Ruby语法解析器忽略,这个关键字之后可以包含任意格式的内容,Ruby可以通过IO库读取这些内容。
  4. 你可以把代码放在多个ruby文件中,在需要的时候通过require关键字导入你需要的模块。Ruby会在特定的路径中所有你所需的模块。
下面是一个例子:
#!/usr/bin/ruby -w          shebang comment
# -*- coding: utf-8 -*- 代码注释
require 'socket' # 导入socket 类库

#程序代码

__END__ #标记代码的结束
#程序数据

(7)Ruby 中的块结构

Ruby中存在块结构的概念,在模块、类和方法中都会用到它。块一般通过符号或者关键字定义,比如下面的代码就是一个
3.times { print "Ruby! " }

这种通过花括号包含起来的代码段,通常与迭代有关。还有一种是通过关键字do 和 and 声明的,尤其是当逻辑较多无法用一行代码描述清楚的情况下,通常使用这种方法:
1.upto(10) do |x|
print x
end

为了区别于其他代码块,我们称其他的代码块为内容体。比如if语句的开始和结束,一个循环的开始和结束,他们之间包含的内容为内容体:
module Stats                          # 一个模块
class Dataset # 模块中的一个类
def initialize(filename) # 类中的一个方法
IO.foreach(filename) do |line| # 方法中的一个块
if line[0,1] == "#" # if语句
next # 一个简单的打印语句
end # 结束if语句的内容体
end # 结束块
end # 结束方法体
end # 结束类内容体
end # 结束模块内容体

(6)Ruby中的“空白”

“空格”、“制表符”以及“换行符”不是具体的符号,但是他们实际上是存在的,Ruby中通常会忽略他们,他们的存在一般是为了格式化代码,是代码看起来更加容易阅读。但是有的时候增加或者删除一个“空白”,会改变程序的含义,这虽然不常发生但是仍然非常重要。
通常情况下在Ruby中一个新的开始意味着上一行语句的结束,在类似C和Java这样的语言中通常一个语句的结束是通过分号表示的,在Ruby中你也可以这样做,但是这不是必须的除非你想在一行中写多个语句。在没有通过分号明确的结束一个语句的情况下,Ruby会判断这一行代码是非从语义上已经结束了,如果没有它会接着解析下一行,比如下面的例子:

x=1
y=3
total=x+
y
puts total #打印的结果为x+y的合计值


x=1
y=3
total=x
+y #这一行是不参与计算的
puts total #打印的结果为x的值

另外要注意的一点是当Ruby遇到break和return关键字的时候则意味着关键字之前的语句已经结束。当然,return是可选的,Ruby认为方法的最后一行就是它的返回值。
你还可以利用反斜杠来避免一行语句的结束,比如:
var total = first_long_variable_name + second_long_variable_name \
+ third_long_variable_name # 注意上一行语句并没有结束

在Ruby1.9中语句结束的规则有一个小小的改变,比如下面的例子中如果你写出一个方法的链式调用,即每个方法以句点开头,这是允许的:
animals = Array.new
.push("dog") # Ruby 1.8不支持此语法结构
.push("cow")
.push("cat")
.sort

说完了换行符号,我们再来看看空格,Ruby中运行在方法后使用括号()来进行方法调用和参数传递,你也可以不使用括号,这是Ruby语言设计上的高明之处,但是这也同样带来了一个致命的“空白”问题,比如下面的例子:
f(3+2)+1
f (3+2)+1

第一行是给方法f传递一个参数3+2并且将结果与1相加,但是第二行中,方法f后面加了一个空格,结果变成了给方法f传递一个参数(3+2)+1 即6,这显然是不对的,如果你通过ruby -w 的方式运行程序你会看到Ruby提示这段代码存在语法混淆的警告。解决这种错误的方法是:
  • 不要再方法名和括号之间加空格。
  • 如果方法的第一个参数一定要包含于一对括号中,那么把所有的参数都用一个大的括号包含起来,比如f((3+2)+1)
  • 总是通过ruby -w 的方式打开警告开关选项,以便在出现语法混淆的时候给出警告。

(5)Ruby中的关键字

下列关键字在Ruby中有特殊的含义:

__LINE__      case         ensure       not          then
__ENCODING__ class false or true
__FILE__ def for redo undef
BEGIN defined? if rescue unless
END do in retry until
alias else module return when
and elsif next self while
begin end nil super yield
break
除此之外,以下三个关键字如果出现在代码行的开头,那么他们有特殊的含义:
=begin =end __END__
就像我们前面介绍的那样,=begin和=end 用于多行注释,__END__代表一段程序的结束,他的前后都不能有其他字符。
以上提到的关键字在其它语言里通常被称为“保留字”,也就是说你不可以把它们当作变量、类名等使用,但是在Ruby中如果你以$,@,@@开头来使用这些关键字是没有问题,它们仍然被当作你自己的标识符,但是我们建议最好不要这样做,这样容易引起歧义,不利于代码阅读。
很多Ruby的重要特性都实现为了相应的方法,所以我们最好把下面的关键字也作为保留字对待:

# 这些为出现在语句中的关键字
at_exit catch private require
attr include proc throw
attr_accessor lambda protected
attr_reader load public
attr_writer loop raise

# 这些为通常的全局函数
Array chomp! gsub! select
Float chop iterator? sleep
Integer chop! load split
String eval open sprintf
URI exec p srand
abort exit print sub
autoload exit! printf sub!
autoload? fail putc syscall
binding fork puts system
block_given? format rand test
callcc getc readline trap
caller gets readlines warn
chomp gsub scan

# 这些为通常用于对象的方法
allocate freeze kind_of? superclass
clone frozen? method taint
display hash methods tainted?
dup id new to_a
enum_for inherited nil? to_enum
eql? inspect object_id to_s
equal? instance_of? respond_to? untaint
extend is_a? send

(4)Ruby 中的标点符号

Ruby 中的标点符号可以用于标识符的开头或者结尾:
  • $:全局变量标识以美元符号开头,类似Perl语言的语法,Ruby定义了一系列的全局变量表示,比如$-,$-K 等等,后面的章节会提供详细的全局变量列表。
  • @:局部变量标识。对于类变量使用两个@开头,后面的章节会介绍如何使用局部变量。
  • ?:问号用于方法名之后,它可以返回一个布尔值
  • !:如果方法名后有一个叹号,这表明你要小心使用,因为这个方法会改变对象本身的内容。
  • =:如果方法名后有一个等号,你可以通过赋值操作的方式调用方法,后面的章节会详细介绍。



$files # 一个全局变量
@data # 一个局部变量
@@counter # A class variable
empty? # 一个返回布尔值的方法
sort! # 一个会改变对象内容的方法
timeout= # 可以通过赋值操作调用的方法

顺便提一下,Ruby中所有的表达符号操作符的实现为一个对应的方法,所以你可以方便的重载他们以实现你自己的逻辑。

(3)Ruby中的标识符

Ruby的标识符用于标识方法、类、模块或者变量名,可以包含任意英文字母、数字和下划线(除下划线以为的其他字符不能包含在标识符中),标识符可以以下划线开头但是不能以数字开头:

i
x2
old_value
_internal # 可以以下划线开头
PI # 静态变量

按照惯例,含有多个单词的标识符以下划线链接或者采用驼峰式写法:


HelloWorld
HELLO_WORD
但是一般不这样写:
hello_world


值得注意的是,Ruby是大小写敏感的,比如关键字end和END是完全不同的。

(2)内嵌文档

我们前面提到,Ruby的#注释方式不支持注释内容的换行,也没有类似Java的/*....*/,注释方式,不过Ruby提供了另一种多行注释方式,你可以以=begin开头=end结尾,包含在这个两个关键字中的内容会被当作注释内容,并且不会被Ruby语法解析器解析:


=begin
多行文本注释的例子,
你可以在其中写任意内容,甚至是其他语言的代码片段,
所有这其中的内容都会被Ruby语法解析器忽略。
=end

这里需要注意的一点是,以上提到的注释方式必须以=begin开头并以=end结尾,如果你在使用#注释的方式,那么就不生效了,比如下面:


#=begin
这里的内容不再是注释
#=end

Ruby 提供了一个rdoc工具,你可以通过它来查看一个模块、类或者方法的说明文档,在你自己编写一个类的时候你可以在类的开头加入注释内容,说明你这个类是干什么的,或者一个方法是完成什么工作的,那么通过Ruby的rdoc工具,其它的人就可以很容易的知道这个类、模块或者方法的细节,你可以在每行开头使用#来添加文档注释,也可以使用=begin和=end,具体的内容可以参考 lib/rdoc/README 中描述的内容。

(1)Ruby 中的注释

Ruby中的注释以#开头,#后所有的内容在Ruby语法解析器都会忽略它,值得注意的是Ruby解析器只#后当前行的内容为主是内容,如果是新的一行中的内容就不认为他是注释了。而且,如果#包含在一个字符串中,那么它被视为字符串的一部分,而不是注释内容,如果#出现在正则表达式中,那么它被认为是正则表达式的一部分而不是注释内容:

# 这是一个注释
x = "#这是一个字符串" # 这也是一个注释
y = /#这是一个正则表达式/ # 另一个注释

所以,如果你要写多行注释,那么每行都要以#开头:
#多行注释
#要以多个'#'开头

值得注意的是,Ruby中不提供类似Java的/*....*/注释方式。