Showing posts with label 表达式与操作符. Show all posts
Showing posts with label 表达式与操作符. Show all posts

Tuesday, October 21, 2008

(5)赋值操作

在Ruby中复制操作通过=实现,这个我们前面一再提到。比如:
x+=1 #等同于x=x+
x*=1 #等同于x=x*1
x,y,z=1,2,3 #Ruby中的平行赋值,x=1,y=2,z=3
x,y,z=[1,2,3] #Ruby中的平行赋值,等号右边可以是一个数组,x=1,y=2,z=3
这些都很好理解,我主要想说说两个特殊情况。局部变量和平行赋值:
对于局部变量,因为没有类似全局变量的符号前缀,所以Ruby无法区分你现在用的x是一个局部变量还是一个方法,在这种情况下,如果你给x赋值那么Ruby认为这是一个局部变量。看下面的代码:
class Ambiguous
  def x; 1; end # 定义一个方法x,返回值为 1

  def test
    puts x      # 没有找到变量名为x,所以调用上面定义的方法:打印 1

    # 因为 "if false" 下面的第一行的赋值不会被执行. 但是
# Ruby解析器已经把他视为一个局部变量了.
    x = 0 if false

    puts x    # 现在x是一个变量但是没有被赋值: 打印nil

    x = 2     # 赋值为2
    puts x    # 所以现在打印 2
  end
end 
 
说到平行赋值,考虑下面的情况,如果等号左边只有一个变量,而右边有多个值,这种情况Ruby会将右边的值转换为一个数组:
x = 1, 2, 3      # x = [1,2,3]
但是如果左边的变量后有一个逗号,结果就不同了:
x, = 1, 2, 3   
  # x = 1;
 其他的值被忽略了
如果等号两边的变量和值不同,结果也不同:
Created with colorer-take5 library. Type 'ruby'

x, y = 1, 2, 3 # x=1; y=2; 3 is not assigned anywhere
#*有特殊的含义,表示后面是一个单独的数组
x, y, z = 1, *[2,3]  # Same as x,y,z = 1,2,3
x,*y = 1, 2, 3  # x=1; y=[2,3]
x,*y = 1, 2     # x=1; y=[2]
x,*y = 1        # x=1; y=[]
#如果存在括号,那么括号内的变量对应等号右边的相应值
x,y,z = 1,[2,3]             #  没有括号:x=1;y=[2,3];z=nil
x,(y,z) = 1,[2,3]           #  加上了括号:x=1;y=2;z=3
a,b,c,d = [1,[2,[3,4]]]     #  没有括号:a=1;b=[2,[3,4]];c=d=nil
a,(b,(c,d)) = [1,[2,[3,4]]] #  加上了括号:a=1;b=2;c=3;d=4
另外需要注意的一点是,如果平行赋值出现在一个方法的后面,Ruby会把逗号分隔的部分当作是方法的参数:
puts x,y=1,2 #Ruby会认为你给puts方法赋值x , y=1 和2 这3个参数。

(4)方法调用

以下四点说明了什么是方法调用:
  1. 方法的调用通过.或者::触发。如果省略了.和::那么说明是在调用自己的方法。
  2. 方法通过方法名调用。
  3. 方法的参数放在一对括号内并用逗号分隔,调用方法是在括号内传递参数,当然括号也不是必须的,你只要顺序给出参数值,并用逗号隔开就可以了。
  4. 另外,一个块(用花括号或者do/end关键字定义的)可以在其中通过yield关键字调用。块和迭代是Ruby提供的强大功能,我们将在后面详细介绍。

puts "hello world"  # "puts" 方法有一个字符串参数
Math.sqrt(2) # "sqrt" Math.sqrt方法有一个参数
message.length # "length" 方法返回message的长度,没有参数
a.each {|x| p x } # "each" 方法在块内部自动执行。
我们看看前面代码中的puts 方法,它是一个全局方法定义在Ruby的kernel中,它可以在任何地方使用。

(3)常量

常量和变量类似,只不过它的值一直保持不变,当然Ruby没有强制规定你不能修改常量的值,只不过如果你修改一个常量的值时会得到一个警告信息。表面上看起来常量和变量没什么区别,不过常量一般以大写字母开头,通常我们会把常量的所有字母都大写LIKE_THIS,并且在每个单词之间用下划线分隔。Ruby中的类目和模块名也是常量,不过它们通常使用每个单词首字母大写的驼峰式写法LikeThis。
常量的特性有些像全局变量,它可以在程序任何地方被引用,但和全局变量不同他可以在类或者模块中定义。
CM_PER_INCH = 2.54  # 定义一个常量.
CM_PER_INCH # 使用这个常量.
如果你在一个类或者模块中定义了一个常量,那么在引用这个常量的时候需要加上类或者模块前缀。
class Master
PP=2.00
end
puts Master::PP

有时候,模块是嵌入到另一个模块中的,这中情况下对常量的引用可以这样写:
Conversions::Area::HECTARES_PER_ACRE

如果一个常量存在于全局范围,那么::前面的内容可以省略:
::ARGV      # 全局常量 ARGV
需要注意的是我们这里说到的“全局”,实际上就是Object类内,也就是说上面的常量实际上是Object::ARGV。
而且如果没有给常量赋值,那么在调用这个常量的时候你会得到NameError异常。


Monday, October 20, 2008

(2)变量

变量就是一个值得名字,创建一个变量的过程就是给这个变量赋值,如果变量出现在等号的左边就是把这个变量的引用赋值给另一个变量。在Ruby中有4中不同类型的变量,以$开头的变量是全局变量,它在整个应用程序中都是有效的;以@和@@开头的变量代表实例变量和类变量;如果变量以下划线_或者消息字母开头,则说明这个变量是一个局部变量。如果在变量中有::说明你要定义一个静态变量比如Math::PI。如果出现点号. 说明你要调用变量所代表的对象的一个方法。Ruby在开始运行的时候还会初始化一系列的全局变量,有关这部分我们后面会讲到。
通常情况下你应该在使用变量前先给变量赋值,或者说初始化这个变量。在某些情况下,你也可以不初始化变量,这在Ruby中是允许的,不过必须遵循一定的规则:
  • 类变量:对于类变量,在使用之前你必须给它赋值,否则你会得到一个NameError的异常。
  • 实例变量:如果你使用了一个未初始化的实例变量,你会得到一个nil值,通常这不是好的编程习惯,如果你打开Ruby的-w选项你会得到一个警告信息。
  • 全局变量:和实例变量一样,如果你使用了未初始化的实例变量,你会得到一个nil值。
  • 局部变量:局部变量比较复杂,因为和其他变量不同,它没有一个明确的符号标记,标明它是一个局部变量还是一个方法调用。如果Ruby解析器识别到一个变量被赋值了,那么它知道这是一个局部变量而不是方法,如果没有赋值操作,Ruby会把它当作是一个方法调用,如果没有这样一个方法,哦,你会得到一个NameError异常。通常,如果一个局部变量没有明确的赋值,Ruby会认为它的值是nil。比如:

a = 0.0 if false    # 这个赋值操作永远不会执行。
print a # 打印nil,即使存在这样一个变量,但是它的值为nil。
print b # NameError: 不存在的变量或者方法。

(1)文字内容与关键字

Ruby中的表达式就是一段代码块,Ruby解析器可以通过它计算并得到一个值。下面是一些例子:
2                  # 一个数字
x # 一个本地变量
Math.sqrt(2) # 一个方法调用
x = Math.sqrt(2) # 赋值操作
x*x # 乘法操作
很多语言在表达式语句(比如条件控制语句和循环语句)之间作了明确的区分。语句只负责执行程序的流程,它们本身是没有值得,它们用于执行而不是计算。在Ruby中没有这样明确的区分,任何语句,包括类、方法都可以被看作是表达式并且都会返回一个值。
值得注意的是很多表达式属于初级表达式,它们是最简单的表达式类型,它们不可能由其他的表达式组成,比如数字。其它的表达式诸如数组、字典对象等不属于初级表达式。一些Ruby中的初级表达式有其特殊的含义,我们可以把它们成为关键字:
  • nil:代表空对象。
  • true
  • false
  • self:代表对象本身,相当于java中的this
  • __FILE__:是一个字符串,它表示一个Ruby可以操作的文件名,这对于处理异常信息非常有用。
  • __LINE__:结合__FILE__对象使用,它是一个整数,代表文件中的某一行。
  • __ENCODING__:在Ruby1.9中它用于指定编码格式,比如utf-8。