Ruby之self详解(一)详细剖析
来源:互联网 发布:datax导入数据到hive 编辑:程序博客网 时间:2024/06/06 11:32
- 博客分类:
- Ruby_and_Rails
简单来说,ruby中的self的含义,要看其上下文。
self上下文
Ruby的self有和Java的this相似之处,但又大不相同。Java的方法都是在实例方法中引用,所以this一般都是指向当前对象的。而 Ruby的代码逐行执行,所以在不同的上下文(context)self就有了不同的含义,先来看看常见的context self都代表哪些
Ruby代码- # 这个位置位于top level context,代表Object的默认对象main
- p self # => main
- p self.class # => Object
- @self1 = self
- # 因为所有自定义类都位于main context之中,所以这是Object的实例方法
- # 同时也可以说是一个全局方法
- def a_method
- @self2 = self
- p self
- # => main,因为有了实例变量@self1和@self2,所以打印出来的不是main这个字符
- # => 但仍然是main对象,注释掉4,8行即可看到效果
- p @self1 == @self2 # => true
- end
- # 下面是一个关于类中不同上下文的self
- class Person
- p self # => Person,代表当前类
- def instance_method
- p self # => #<Person:0xb7818fdc>,代表当前类的实例
- end
- def self.class_method
- p self # => Person,和第16行一样代表当前类(这是类方法的context),它们是相等的
- end
- end
- m = Person.new
- def m.hello
- p self # => 代表m这个单例对象
- end
- m.hello
上面只写了在类中的self,其实在module也是一样的。通过上面代码你可以发现,self一直引用着它所在位置上下文的实例 (类也是一个实例)(其实这是跟java等一样的,合乎面向对象的要求,self/this指向自己) 。
self显式/隐式
你可以先试着运行下面代码,看看有什么意外发生没有
Ruby代码- class Person
- attr_accessor :name
- def set_name(your_name)
- name = your_name
- end
- end
- m = Person.new
- p m.name
- m.set_name('today')
- p m.name # => 猜是什么
如果你猜是today就大错特错了,答案是nil,为什么是nil呢,在第5行,我明明调用的是attr_accessor生成的name=方法赋值的啊,你可以在前面加上self试试,代码如你预期的一样执行了。在这种情况下name = your_name并没有去调用attr_accessor生成的xx=方法,而是将name当作了一个局部变量,如果显式的指定self,就没有问题了。
(另外,请注意,ruby中的实例变量要有@号,所以此处不用self,而用@name,也是可以的)
读到这,你是不是认为以后这种情况就一直用显式self去调用就好了,其实不然,下面的代码仍会说明一些问题
Ruby代码- class Person
- public
- def get_my_secret1
- my_secret # => 隐式
- end
- def get_my_secret2
- self.my_secret # => 显式
- end
- private
- def my_secret
- p 'something...'
- end
- def self.secret
- p 'nothing'
- end
- class << Person
- def method3
- p 'method3'
- end
- private
- def method4
- p 'method4'
- end
- end
- end
- m = Person.new
- #m.my_secret # => private method error
- Person.secret # => nothing
- Person.method3 #fantaxy added here!
- Person.method4 #fantaxy added here! #NoMethodError: private method `method4' called for Person:Class
- m.get_my_secret1 # => something
- m.get_my_secret2 # => private method error
上面代码说明:
第一个问题,显式self不可以调用private(protected的也一样)方法,而隐式的可以(这个原因我在下面解释) 。
原因是什么?
Ruby代码- self.my_secret # => 显式
- #这一句的self在实例方法内,所以self指的是Person的一个实例,而实例是不能调用私有方法的(protected也如此)
- #注意,此时的self和我们new一个Person的实例没有本质区别。
第二个问题,本来:权限修饰符只对实例方法生效(下面解释),但是这里类方法也受限制了。
解释:
ruby中类也是一个实例,给类这个实例加入实例方法,也会有private/protected之分。
Ruby代码- class << Person #给实例(Person)添加实例方法
- def method3
- p 'method3'
- end
- private
- def method4
- p 'method4'
- end
- end
self“怪异”写法
下面代码被我个人称为怪异写法,因为平时用不到,但偶尔会看到,但看起来又不太直观,这里列举一下
Ruby代码
- class Person
- def metaclass
- class << self #这是ruby中单例的语法,其本质是生成一个self的单例类(虚类)|域
- #因为上面的self在实例方法内,因此指的是Person的一个实例,所以会生成实例的单例类(不是类的单例类)
- #下面返回的self,是在单例类的作用域内,所以指的是其本身,即单例类本身(虚类)
- # 有些人比较迷惑,我打印出self是Person啊,这是由于ruby的实现问题,并不打印虚类本身,
- # 而是打印虚类的super类的类名,此处即Person类(X类的对象x,x的虚类的super指向X)
- self
- end
- end
- def metaclass2
- self #实例作用域
- end
- end
- a = Person.new
- b = a.metaclass
- c = a.metaclass2
- # 首先要明白,类Person是Class的一个“实例”,a是Person的一个实例
- # 这里b也是一个Person类,但它是独一无二的,即你修改Person不会影响到b,反之亦然
- p b # => #<Class:#<Person:0xb76f3800>>
- p b.class # => Class
- class Person
- def hello
- p 'hello Person'
- end
- end
- class << b
- def hello
- p 'hello b'
- end
- end
- b.hello # => hello b
- p c # => #<Person:0xb76f3800>
- p c.class # => Person
- c.hello # => hello Person
Ruby代码
- class Person
- def self.hello
- p 'hello'
- end
- class << self
- # 看了最上面self和context的关系,你应该知道这个self代表是Person类
- # 在这里为Person添加方法,其实也就是为Person添加类方法,和上面的self.hello异曲同工
- def work
- p 'hard work'
- end
- end
- end
- Person.work
明白了self之后,看看下面的用法:ruby 的 extend self
我们想让实例方法同时为类方法,那么可以使用extend self,这个对于普通的类
可能没有什么用。但是对于module来说还是很有用的,因为module不可以实例化,
module的实例方法通过自身就无法单元测试,所以通过extend self可以作为类方法暴露
来测试了:
Ruby代码
- module M
- extend self
- def greeting
- puts "hi"
- end
- end
如果没有extend self,我们就无法使用M.greeting,
现在我们可以调用M.greeting了。
BTW:
module_function可以把module一个实例方法变成私有的,并复制一份放到其metaclass中。
参考:
http://ilstar.blogbus.com/logs/59782933.html
http://fuliang.iteye.com/blog/827443
- Ruby之self详解(一)详细剖析
- Ruby之self,上下文
- Ruby之self,上下文
- 笔记之Ruby(一)
- ruby学习之实例变量与self
- OC之self详解
- Ruby Profiler详解之ruby-prof(I)
- ruby学习之路(一)
- Ruby Profiler详解之stackprof
- Android Service 详解一(超详细)
- Android自定义属性详细剖析(一)
- Android自定义属性详细剖析(一)
- Ruby 语法(一)
- Ruby 教程(一)
- ruby札记(一)
- Ruby 基础知识(一)
- Ruby基础(一)
- 链表剖析之单链表剖析(一)
- 本来:权限修饰符只对实例方法生效(下面解释),但是这里类方法也受限制
- Hibernate中对象的三种状态
- 三角形的面积问题
- 关于快速排序的见解(分治法)
- sp与isag的开发包短信彩信
- Ruby之self详解(一)详细剖析
- main函数的参数(argc和argv)
- sp与ISMP接口开发包1短信彩信
- Hibernate悲观锁和乐观锁详解
- PHP session原理总结
- POJ Problem Id1006 :Biorhythms ACM 编程练习
- 下拉菜单
- poj 1321棋盘问题
- 5311 Exponentiation