Ruby中的self剖析

这部分其实也是基础知识的一部分,但是这是元编程很重要的一环,所以单独拿出来写一下,希望可以帮助自己的更好理解它的思想和用法。

self上下文
Ruby的self有和Java的this已经C++的this指针都有相似之处,但又大不相同。Java的方法都是在实例方法中引用,所以this一般都是指向当前对象的。而 Ruby的代码逐行执行,所以在不同的上下文(context)self就有了不同的含义,先来看看常见的context self都有哪些例子。

顶层上下文中的self
我们已经知道任何时刻只要调用某个对象的方法,这个对象就成为self。如果我们还没有调用任何方法,这个self是谁呢?

当我们直接打开irb,这个位置位于top level context,代表Object的默认对象main:

p self # => main   
p self.class # => Object    
@self1 = self  

# 因为所有自定义类都位于main context之中,所以这是Object的实例方法   
# 同时也可以说是一个全局方法   

def a_method   
  @self2 = self  
  p self      
  p @self1 == @self2 # => true   
end

Ruby程序开始运行时,Ruby解释器会创建一个名为main的对象作为当前对象,这个对象有时候称为顶层上下文。这个名字的由来是因为这时你处在调用堆栈的顶层,要么还没有调用任何方法,要么调用的所有方法都已经返回。

通过上面代码你可以发现,self一直引用着它所在位置上下文的实例 (类也是一个实例)。这是跟java等一样的,合乎面向对象的要求,self/this指向自己)

类中不同上下文的self
首先我们先来看看在同一个类中的不同位置的不同上下文。在这里可以很明显看出类方法和实例方法的区别。

class Person   
  p self # => Person,代表当前类   

  def instance_method   
    p self # => #<Person:0xb7818fdc>,代表当前类的实例   
  end  

  def self.class_method   
    p self # => Person,当前类(这是类方法的context)   
  end  
end 

Person.class_method
m = Person.new  
m.instance_method

class << self的用法

class Person     
  def self.hello     
    p 'hello'    
  end   

  def hello_instance   
    p 'hello_instance'    
  end   

  class << self 
    # 看了最上面self和context的关系,你应该知道这个self代表是Person类     
    # 在这里为Person添加方法,其实也就是为Person添加类方法,和上面的self.hello异曲同工之妙
    def work     
      p 'hard work'    
    end    
  end    
end    

Person.hello  
Person.work   

a=Person.new  
a.hello_instance 

extent self

我们想让实例方法同时为类方法,那么可以使用extend self,这个对于普通的类 可能没有什么用。但是对于module来说还是很有用的,因为module不可以实例化, module的实例方法通过自身就无法单元测试,所以通过extend self可以作为类方法暴露来测试了:

module M   
  extend self  
  def greeting   
    puts "hi"  
  end  
end  

如果没有extend self,我们就无法使用M.greeting

self显式/隐式调用

class Person   
  attr_accessor :name  

  def set_name(your_name)   
    name = your_name    
  end  
end

m = Person.new     
m.set_name('today')   
p m.name 

最后打印的name会是nil,在这种情况下name = your_name并没有去调用attr_accessor生成的@name=方法,而是将name当作了一个局部变量,如果显式的指定self或者使用实例变量@name,就没有问题了。

猜你喜欢

转载自blog.csdn.net/zyhmz/article/details/80261815
今日推荐