Ruby 实例变量

  Ruby要求实例变量以“@”符号开头。与静态语言不同的是, Ruby语言是一门动态语言,因此 Ruby的实例变量无须声明,每个实例变量都是在第一次出现时动态加入对象。
因此, Ruby的实例变量通常在方法中定义类声明——当在方法里声明实例变量时,该实例变量实际上属于该方法所在类的实例,而不是属于该方法。
看下面的程序:
  1. class Apple     
  2.     # 定义第一个方法      
  3.     def info1     
  4.         # 输出实例变量@a      
  5.         puts @a    
  6.     end    
  7.     # 定义第二个方法      
  8.     def info2     
  9.         # 为实例变量赋值      
  10.         @a = "Hello";     
  11.     end    
  12. end    
  13. # 创建Apple类实例      
  14. apple = Apple.new    
  15. # 调用方法      
  16. apple.info2     
  17. apple.info1    

从上面的方法中不难看出,虽然定义第一个方法info1时,该方法内输出的@a实例变量还没有被定义,但这不是问题!因为Ruby的方法只有在被调用时才会真正生效,所以当调用apple.info2方法时,执行了@a = "Hello"代码,这行代码动态地为apple实例增加了一个@a实例变量。

注意:Java创建对象时一次为该对象的所有实例变量都分配了相应的内存空间;但Ruby语言里的对象完全是动态的,创建对象时该对象没有任何实例变量,直到执行到为实例变量定义时,该对象才动态增加该实例变量。

类似于全局变量,实例变量无须显式声明即可使用。如果使用一个未定义的实例变量,则该实例变量的值为nil。
与局部变量不同是的:实例变量的生存范围是与该对象的生存范围相同的,只要该类的对象存在,则该对象里的实例变量将一直存在;但局部变量则随方法的消亡而消亡(除非使用闭包)。
实例变量的访问范围总是private,这意味着在类定义内对实例变量的赋值和读取没有限制;如果希望在类外部访问到实例变量的值,则可以通过方法来访问。看如下代码:

  1. class Apple     
  2.     # initialize是一个特殊方法,其实就是一个构造器,在创建Apple实例时自动调用      
  3.     def initialize(name)     
  4.         # 当执行构造器时添加一个实例变量      
  5.         @name=name     
  6.     end    
  7.     # 定义一个与name实例变量同名的方法,该方法返回实例变量@name      
  8.     def name     
  9.         return @name      
  10.     end    
  11.     # 定义一个名为name=的方法,该方法用于为@name实例变量赋值      
  12.     def name=(att)      
  13.         @name=att     
  14.     end        
  15. end    
  16. # 创建Apple的实例      
  17. a = Apple.new("红富士")     
  18. # 通过name方法来访问@name实例变量      
  19. puts a.name     
  20. # 通过调用name=方法来为@name实例变量设置值      
  21. a.name = "青苹果"    
  22. puts a.name    

执行上面的代码,看到如下执行结果:
红富士
青苹果

从上面的代码中不难看出,Ruby语言里的实例变量可以被定义成一个属性。实际上,Ruby为定义类里的属性提供了更简单的方法:通过Module的方法定义属性。

这种用法并不是Ruby语法的一部分,它只是通过使用Module类里几个方法来自动创建属性。
看如下代码:

  1. class Apple     
  2.     # 使用attr创建了一个@name实例变量,且为该变量创建了读取方法      
  3.     attr :name    
  4.     # 使用attr创建了一个@color实例变量,且为该变量创建了读取和设值方法      
  5. attr :color ,true    
  6.     # 使用attr_reader创建了一个@weight实例变量,且为该变量创建了读取方法      
  7.     attr_reader :weight    
  8.     # 使用attr_ writer创建了一个@size实例变量,且为该变量创建了设值方法      
  9.     attr_writer :size        
  10.     # 使用attr_accessor创建了一个@info实例变量,且为该变量创建了读取和设值方法      
  11.     attr_accessor :info    
  12. end    
  13. a = Apple.new    
  14. # @name属性只可访问      
  15. puts a.name     
  16. # @color属性既可设值,也可访问      
  17. a.color = "红色"    
  18. puts a.color     
  19. # @weight属性只可访问      
  20. puts a.weight     
  21. # @size属性只可设值      
  22. a.size = 0.2;     
  23. # @info属性既可设值,也可访问      
  24. a.info = "可口的水果"    
  25. puts a.info    

上面的代码的执行结果如下:
nil
红色
nil
可口的水果

从上面的代码中不难看出,通过Module里的4个方法attr,attr_reader,attr_writer和attr_accessor来创建实例变量及其对应的访问方法更加简单。
实际上,上面的Apple类相当于如下代码。

  1. class Apple     
  2.     # 定义name的访问方法      
  3.     def name     
  4.         return @name    
  5.     end    
  6.     # 定义color的访问方法      
  7.     def color     
  8.         return @color    
  9.     end    
  10.     # 定义color的设值方法      
  11.     def color=(att)     
  12.         @color = att     
  13.     end    
  14.     # 定义weight的访问方法      
  15.     def weight     
  16.         return @name    
  17.     end    
  18.     # 定义size的设值方法      
  19.     def size=(att)     
  20.         @size = att     
  21.     end    
  22.     # 定义info的访问方法      
  23.     def info     
  24.         return @info    
  25. end    
  26.     # 定义info的设值方法      
  27.     def info=(att)     
  28.         @info = att     
  29.     end    
  30. end    

 除此之外,我们也可以在模块中定义实例变量,在模块中的定义变量的目的并不是用于创建模块的实例(模块是无法创建实例的),而是用于将该实例变量混入其他类中。
在如下代码中,我们在模块里定义了一个实例变量,并将该实例变量混入其他类中。 
 

  1. # 定义一个Vegetable模块      
  2. module Vegetable     
  3.     //在模块里使用attr定义一个@color实例变量     
  4.     attr :color ,true    
  5. end    
  6. # 定义一个Apple类      
  7. class Apple     
  8.     # 混入Vegetable的实例变量      
  9.     include Vegetable     
  10. end    
  11. a = Apple.new    
  12. a.color = "红色"    
  13. puts a.color    

从上面的程序中可以看出,Apple类获得了Vegetable模块中的@color实例变量,这就是在模块中定义实例变量的作用。
从上面的代码中不难看出,虽然实例变量是属于类的,但大部分时候我们都是在该类的方法里定义实例变量,而不是在类中定义实例变量。

在类范围内定义的实例变量属于类对象(Class对象,当我们定义一个类时,该类定义会返回一个Class对象,该对象会保存到一个与该类同名的常量里),类范围内定义的实例变量是Class对象(对象名就是该类的类名)的实例变量,实例变量永远都不能暴露成为public访问控制,只能通过方法暴露,因此类范围的实例变量反而没有太大的意义。

  1. class Apple     
  2.     # 定义一个类范围的实例变量      
  3.     @color = "红色"    
  4.     def info     
  5.         # 方法内无法访问类范围的实例变量      
  6.         puts @color    
  7.     end    
  8.     # 类内才可以访问类范围的实例变量      
  9.     puts "类范围的实例变量 " + @color    
  10. end    
  11. a = Apple.new    
  12. a.info    

上面的代码的执行结果如下:
类范围的实例变量 红色
nil
从上面的执行结果可以看出:在方法内访问类范围的实例变量时结果为nil,这表明方法内无法访问类范围的实例变量。

如果我们希望暴露类范围的实例变量,可以通过定义一个类方法来暴露它。看如下的代码:

  1. class Test     
  2.     # 定义一个类范围的实例变量@name,该实例变量属于Class类的实例(该实例名为Test)      
  3.     @name = "孙悟空";     
  4.     def name=(value)     
  5.         # 定义属于Test实例的实例变量      
  6.         @name = value     
  7.     end    
  8.     # 定义一个类方法      
  9.     def Test.name     
  10.         # 类方法的调用者是Test类本身,也就是Class类的实例      
  11.         # 因此,此处访问的是类范围的实例变量      
  12.         @name    
  13.     end    
  14. end    
  15. # 调用Test类的name方法      
  16. puts Test.name    

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值