| |||
上一章 < | 目录 ^ |
下一章 > |
KCODE
选项就应该被适当地设置,如137页所示。]
Ruby是一种面向行的(line-oriented)程序设计语言。Ruby的表达式和声明语句都是在一行的最后结束,除非一个语句很明显是没有结束的---比如一行的最后一个字符是一个操作符或者逗号。一个分号可以用来分割一行中的多个语句。你也可以在一行最后加一个反斜杠来使这一行延续到下一行。注释以'#'开始,到物理行结束为止。在编译(执行)的时候,注释将被忽略。
a = 1b = 2; c = 3 d = 4 + 5 + #不需要'\' 6 + 7 e = 8 + 9 \ + 10 #需要'\' |
stdin
发送程序代码。
echo 'print "Hello\n"' | ruby |
__END__
”的代码,没有前行和后随的空格,它就把这一行当成程序的结束---后面的所有代码都不会被编译了。然而,后面的代码可以用一个全局IO
对象DATA
读入正在执行的当前程序,这在217页有描述。
BEGIN
模块)或者在程序执行结束后(END
模块)运行。
BEGIN { begin code }END { end code } |
BEGIN
和END
模块。BEGIN
模块以它们出现的顺序执行,END
模块以相反的顺序执行。
常规定界输入
|
(
”,“[
”,“{
”,“<
”中的一个,那么常量由分隔符到相应的后随结束符(译者注:比如左括号'('对右括号')')之间的字符组成,注意嵌套的分隔符。对于其他的分隔符,常量由两个分隔符之间的字符组成。
%q/this is a string/ %q-string- %q(a (nested) string) |
%q{def fred(a) a.each { |i| puts i } end} |
Fixnum
或者Bignum
的对象。Fixnum
可以容纳物理机器一个字长少一位大小的整数。当一个Fixnum
超过它的范围时,它会自动转换成Bignum
类型,而Bignum
类型的范围只能被物理内存所限制。如果一个Bignum
上的操作使得它的最终值适合一个Fixnum
保存,那么结果就会以一个Fixnum
对象返回。
整数前面可以带一个可选的符号标记,一个可选的进制指示符(0
代表八进制,0x
代表十六进制,0b
代表二进制),然后跟一串相应进制的数字串。在数字串中的下划线将被忽略。
你可以在一个ASCII字符前面加一个问号来取得它相应的整数值。Ctrl和Meta(译者注:Meta就是Alt键)的键组合可以由?\C-x, ?\M-x, 和?\M-\C-x来产生。一个字符ch
的Ctrl版本是(就是Ctrl + ch组合)ch&0x9f
,然后它的Meta版本是ch | 0x80
。你可以用字符序列?\\
来取得反斜杠的整数值。
123456 # Fixnum 123_456 # Fixnum (下划线被忽略) -543 # Negative Fixnum 123_456_789_123_345_789 # Bignum 0xaabb # 十六进制 0377 # 八进制 -0b1010 # 二进制 (负的) 0b001_001 # 二进制 ?a # character code ?A # upper case ?\C-a # control a = A - 0x40 ?\C-A # case ignored for control chars ?\M-a # meta sets bit 7 ?\M-\C-a # meta and control a |
Float
对象,大小和物理机器上double
类型一样。你必须在小数点后面跟一个数字,因为像1.e3
意味着去调用类Fixnum
的方法e3
。
12.34 |
12.34 | |
-.1234e2 |
-12.34 | |
1234e-2 |
12.34 |
String
对象。每种方法在字符串是如何定界和要产生多少替换上是不一样的。
单引号字符串('
stuff'
和%q/stuff/)进行最少限度的替换。两种格式的表示方法都把“\\”转换成一个反斜杠,然后把“\'”转换成一个单引号。
'hello' |
hello | |
'a backslash \'\\\'' |
a backslash '\' | |
%q/simple string/ |
simple string | |
%q(nesting (really) works) |
nesting (really) works | |
%q no_blanks_here ; |
no_blanks_here |
双引号字符串中的替换
|
a = 123 | ||
"\123mile" |
Smile | |
"Say \"Hello\"" |
Say "Hello" | |
%Q!"I said 'nuts'," I said! |
"I said 'nuts'," I said | |
%Q{Try #{a + 1}, not #{a - 1}} |
Try 124, not 122 | |
%<Try #{a + 1}, not #{a - 1}> |
Try 124, not 122 | |
"Try #{a + 1}, not #{a - 1}" |
Try 124, not 122 |
a = 123 print <<HERE Double quoted \ here document. Sum = #{a + 1} HEREprint <<-'THERE' This is single quoted. The above used #{a + 1} THERE |
Double quoted here document. Sum = 124 This is single quoted. The above used #{a + 1} |
String
对象。
'Con' "cat" 'en' "ate" |
"Concatenate" |
jcode
库支持一系列对EUC,SJIS,或者UTF-8编码字符串的操作。不过底层的字符串还是以字节形式被访问。],然后每个字节都保存一个256以内的8比特值,包括空值null和换行。203页表18.2所示的替换规则允许不可打印字符可以便利并且可移植地嵌入到普通字符串中。
每一次一个字符串被用在一个赋值或者用做一个参数的时候,一个新的String
对象会被创建。
for i in 1..3 print 'hello'.id, " " end |
537767360 537767070 537767040 |
String
类的详细资料请参见第363页开始的文档。
..
expr和expr...
expr会创建范围对象(Range
)。中间两点的格式不包括两边的边界值;中间有三点的格式还包括最后那个边界值。要看Range
类的详细信息,请参见第359页。第222页有在条件语句中使用范围的其他方法。
Array
的对象由一系列在方括号中由逗号分隔的对象引用组成。最后一个逗号会被忽略。
arr = [ fred, 10, 3.14, "This is a string", barney("pebbles"), ] |
%w
,它可以把由逗号分隔的一个连续字符串中的子字符提取出来组成一个字符串数组。空格可以由反斜杠转义。这是一种定界输入的格式,请参见200--201页。
arr = %w( fred wilma barney betty great\ gazoo ) | ||
arr |
["fred", "wilma", "barney", "betty", "great gazoo"] |
Hash
对象是由一系列在花括号里面的键/值匹配对组成的。由逗号分隔键/值对,键和值之间由=>
连接。最后一个逗号会被忽略。
colors = { "red" => 0xf00, "green" => 0x0f0, "blue" => 0x00f } |
hash
,然后返回一个哈希值,这个哈希值不能改变。这意味着一些类(比如Array
和 Hash
,像这种类型的)不能很好的适合哈希键值的要求,因为它们的值会随着它们的内容而变化。
如果你保持了一个对象的外部引用,然后这个对象又被用来做为一个哈希键。那么你通过这个引用来改变这个对象然后改变哈希值,这个哈希键对应的哈希值将不会起作用。
因为字符串经常被用来当作键值,然后字符串值又会经常改变,Ruby对字符串键值做了特殊处理。当你把一个String
对象当做哈希键时,哈希表会复制一个字符串,然后把这个字符串当作键值。后随的所有对原来字符串的改变不会影响哈希表。
如果你写了自己的类然后把它们的实例当作哈希键值,你必须确保哈希表的键值在创建以后不再改变或者在键值改变的时候记得调用Hash#rehash
方法来重新索引哈希表。
:Object :myVariable |
Regexp
的对象。它们可以通过显式地调用Regexp.new
来创建,或者使用文字常量方式,/pattern/和%r{
pattern}
。%r
创建方法是一种普通定界输入(详见200--201页)。
/pattern/ /pattern/选项 %r{pattern} %r{pattern}选项 Regexp.new( 'pattern' [, 选项 ] ) |
Regexp.new
方法,那么选项就是构造函数的第二个参数。
i |
忽略大小写. 这个匹配将会忽略模式和字符串中的字符的大小写。如果全局变量$= 被设置,那么匹配也会大小写不敏感。 |
o |
替换一次。任何在正则式中的#{...} 替换都仅进行一次,就是第一次遇到它的时候。其他情况中,替换会在每次一个Regexp 对象产生的时候进行。 |
m |
多行模式。通常的,'.'匹配除了换行以外的任何字符。有了/m 选项以后,'.'匹配任何字符了。 |
x |
扩展模式。复杂的正则表达式会很难阅读。'x'选项允许我们可以在模式中加入空格,换行和注释来使它更容易被阅读。 |
^
$
\A
\z
\Z
\b
, \B
[
字符 ]
|, (, ), [, ^, $, *,
和?
,在其他地方有特殊含义,但是在方括号里面就失去了它们的特殊含义。序列 \
nnn, \x
nn, \c
x, \C-
x, \M-
x, and \M-\C-
x有如203页表18.2所示的特殊含义。序列\d
, \D
, \s
, \S
, \w
,和\W
是一组字符串的缩写,如59页表5.1所示。序列c1-c2表示在c1和c2之间的所有字符(包括c1,c]
或-
必须仅跟在左括号后面。一个(^)紧跟在左括号后使匹配反义---模式匹配任何不在方括号中出现的字符。
\d
, \s
, \w
.
(句点)
/m
选项被设置了,那么它也匹配换行符)。
*
+
{m,n}
?
*
, +
, 和{m,n}
都是最大匹配的,加上一个问号使得它们进行最小匹配。
|
re2
|
的优先级很低。
(...)
/abc+/
匹配一个含有一个'a', 一个'b'然后一个或多个'c'的字符串。/(abc)+/
就匹配一次或多次"abc"的出现。圆括号还用来收集模式匹配的结果。Ruby为每一个左圆括号保存括号中的部分匹配结果,直到相应的右括号为止。在同一个匹配中,\1
代表第一组匹配的结果,\2
代表第二组结果,依次类推。在匹配外面,特殊变量$1
, $2
等起到相同的作用。 #{...}
/o
选项被设置时,它仅仅匹配一次。
\0, \1, \2, ... \9, \&, \`, \', \+
(?/code> and )
里面。这些圆括号括着的扩展是组,但是它们不会产生后引用(backreferences):它们不会设置\1
和$1
等变量的值。
(?# 注释)
- 在模式串中插入注释。注释在模式匹配的时候被忽略。
(?:re)
- 把re加入组,然而不产生后引用。这在当你希望创建一个组但是又不想让它设置
$1
等值的时候特别有用。在下面的例子中,两个模式都保存了一个包括月份,日子和年份的数据,用冒号或空格分隔。第一种格式的在$2
和$4
中保存了数据,但是第二种格式没有保存内部数据。
date = "12/25/01"
date =~ %r{(\d+)(/|:)(\d+)(/|:)(\d+)}
[$1,$2,$3,$4,$5]
["12", "/", "25", "/", "01"]
date =~ %r{(\d+)(?:/|:)(\d+)(?:/|:)(\d+)}
[$1,$2,$3]
["12", "25", "01"]
(?=re)
- 在此处匹配re,但是不要销毁它(也可以惬意地叫做零距离回顾(``zero-width positive lookahead''))。它可以让我们方便地引用前面的内容而不会影响
$&
。在这个例子中,scan
方法匹配后面跟一个句点的单词,但是句点不包括在匹配结果里面。
str = "red, white, and blue"
str.scan(/[a-z]+(?=,)/)
?/td>
["red", "white"]
(?!re)
- 看看在此处是否不匹配re。不要销毁这个匹配(否定的零距离回顾)。比如,
/hot(?!dog)(\w+)/
匹配任何包含“hot”然后后面不跟“dog”的单词,返回$1
中的最后一个单词。
(?>re)
- 把一个独立的正则式嵌入到第一个正则式中。这个表达式在当前匹配点被确定。如果它销毁了一些字符,这些字符就不会被上级的正则式访问到。因此这个结构是有后回溯机制的(backtracking),这可以是一个执行效果的增强。比如,模式
/a.*b.*a/
的基本意思是匹配一个含有一个'a',后面跟数个'b',然后没有后随'a'的字符串。然而,这可以用嵌套的正则式/a(?>.*b).*a/
来避免。在这种格式中,内嵌的正则式消耗掉了所有字符串,直到有字符'b'的出现。当一个对后随'a'的查找失败以后,就没有回溯的必要了,这个模式匹配迅速结束。
require "benchmark"
include Benchmark
str = "a" + ("b" * 5000)
bm(8) do |test|
test.report("Normal:") { str =~ /a.*b.*a/ }
test.report("Nested:") { str =~ /a(?>.*b).*a/ }
end
产生结果:
user system total real
Normal: 0.420000 0.000000 0.420000 ( 0.414843)
Nested: 0.000000 0.000000 0.000000 ( 0.001205)
(?imx)
- 打开"i","m"或"x"选项。如果用在一个组里面,那么效果就限制在组里面。
(?-imx)
- 关闭"i","m"或"x"选项。
(?imx:re)
- 打开re的"i","m"或"x"选项。
(?-imx:re)
- 关闭re的"i","m"或"x"选项。
标识名
Ruby的标识名用来指向常量,变量,方法,类和模块。标识名的首字符用来帮助我们确定标识所指向内容的类型。一些标识名,就是210页表18.3所示的都是保留字,不能用来当作变量,方法,类或模块的名字。
保留字
__FILE__
and
def
end
in
or
self
unless
__LINE__
begin
defined?
ensure
module
redo
super
until
BEGIN
break
do
false
next
rescue
then
when
END
case
else
for
nil
retry
true
while
alias
class
elsif
if
not
return
undef
yield
在下面的描述中,小写字母表示'a'到'z'的字母和'_',下划线。大写字母表示'A'到'Z'的字母,还有数字表示'0'到'9'的数字字符。标识符字符表示大小写字母和数字的组合。
一个局部变量由一个小写字母后面跟标识符组成。
fred anObject _x three_two_one
类的实例变量由一个‘@
’开始,后面跟一个大写或小写字母,然后后面还可以有一些标识符字符。
@name @_ @Size
一个类变量由两个‘@@
’开始,后面跟一个大写或小写字母,然后后面还可以有一些标识符字符。
@@name @@_ @@Size
一个常量名由一个大写字母开始,后面跟标识符字符。类名和模块名是常量,所以也遵循常量的命名规则。常量名一般是由大写字母组成,然后可以带下划线。
module Math
PI = 3.1415926
end
class BigBlob
全局变量,以及一些特殊的系统变量,由一个美圆符号'$
'开始,然后后面跟标识符字符。另外,还有一些有两个字符组成的变量名,它们第二个字符是标点符号。这些预设的变量名在213页有描述。最后,全局变量名也可以用"$-
"开头,后面跟任意一个字符。
$params $PROGRAM $! $_ $-a $-.
关于方法的命名规则,在从第225页的开始的章节有描述。
变量/方法的疑惑
每当Ruby在一个表达式中遇到一个比如像'a'这样的字符,他必须确定这个'a'到底是一个局部变量的引用还是一个无参数的函数方法调用。为了确定这个,ruby用了一种启发式(heuristic)的方法。当Ruby在读取源代码的时候,它记下了那些被赋值的标识符。它假定这些标识符是变量名。然后如果它在随后遇到一个标识符可能是变量,也可能是方法名的时候,它就查看这个标识服是否在以前被赋过值。如果被赋过值,它就把标识符当成变量名;否则它就把标识符当成一个方法调用。作为一个比较诡异的例子,请参见以下的代码片段,由Clemens Hintze递交。
def a
print "Function 'a' called\n"
99
end
for i in 1..2 if i == 2 print "a=", a, "\n" else a = 1 print "a=", a, "\n" end end
produces:
a=1
Function 'a' called
a=99
在语法解析的时候,Ruby遇到第一个'a',因为此时'a'没有被赋值,就认为它是一个方法调用。然后到第二个打印语句的时候,Ruby已经遇到了一个赋值,所以此时它把'a'当成一个变量。
注意赋值语句不一定要被执行---Ruby只要见到它就可以了。这个程序不会出现错误。
a = 1 if false; a
变量和常量
Ruby变量和常量都是指向对象的引用。变量自身并没有内在的类型。一个变量的类型仅仅由它指向的对象的信息决定。 [我们说一个变量没有类型,我们的意思就是任何给定的变量可以在不同时间指向许多不同的类型。]
一个Ruby的常量也是对一个对象的引用。常量在Ruby首次对它赋值时被创建(一般在一个类或模块的定义中)。和一些通融性差的语言不同,允许我们修改变量的值,尽管这样会得到一个警告信息。
MY_CONST = 1
MY_CONST = 2 # generates a warning
产生结果:
prog.rb:2: warning: already initialized constant MY_CONST
注意虽然常量不应该被修改,但是我们可以修改它指向的对象的内部状态。
MY_CONST = "Tim"
MY_CONST[0] = "J" #修改常量的内部状态
MY_CONST
"Jim"
赋值潜在地给一个对象别名,给同一个对象不同的名字。
常量和变量的作用域
在一个类或模块中定义的常量可以方便地在类或模块任何地方访问。在模块或类外面,它们可以使用域作用符“::
”来访问,在一个表达式前加一个“::
”可以返回类或模块相应的对象。在任何类外面定义的常量,可以通过在它前面加"::
"访问到。我们不能在方法中定义常量。
OUTER_CONST = 99
class Const
def getConst
CONST
end
CONST = OUTER_CONST + 1
end
Const.new.getConst
100
Const::CONST
100
::OUTER_CONST
99
全局变量在整个程序中都可以使用。每个指向特定全局对象名的引用都返回相同的对象。引用一个未初始化的全局变量返回一个
类变量在整个类或模块体中都可以被使用。类变量在使用之前必须被初始化。一个类变量被这个类的所有对象所共有,然后只在类内部使用。
class Song
@@count = 0
def initialize
@@count += 1
end
def Song.getCount
@@count
end
end
类变量属于最内层嵌套类或模块。最顶层的类变量是定义在Object
中的,然后就像全局变量一样。如果接收者是一个类或者模块,那么定义在单例类里面的类变量属于接收者;否则,它们属于接收者的类。
class Holder
@@var = 99
def Holder.var=(val)
@@var = val
end
end
a = Holder.new def a.var @@var end
上一章 <
目录 ^
下一章 >
Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Copyright © 2001 by Addison Wesley Longman, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/)).
Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.