`
fantaxy025025
  • 浏览: 1346039 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

Ruby之self详解(一)详细剖析

阅读更多

 

简单来说,ruby中的self的含义,要看其上下文。

 

    self上下文

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

# 这个位置位于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显式/隐式

    你可以先试着运行下面代码,看看有什么意外发生没有

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去调用就好了,其实不然,下面的代码仍会说明一些问题

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的也一样)方法,而隐式的可以 (这个原因我在下面解释)

原因是什么?

 self.my_secret # => 显式
#这一句的self在实例方法内,所以self指的是Person的一个实例,而实例是不能调用私有方法的(protected也如此)
#注意,此时的self和我们new一个Person的实例没有本质区别。

 

    第二个问题,本来:权限修饰符只对实例方法生效(下面解释) ,但是这里类方法也受限制了。

解释:

ruby中类也是一个实例,给类这个实例加入实例方法,也会有private/protected之分。

  class << Person #给实例(Person)添加实例方法
    def method3
      p 'method3'
    end

    private
    def method4
      p 'method4'
    end
  end

 

 

    self“怪异”写法

    下面代码被我个人称为怪异写法,因为平时用不到,但偶尔会看到,但看起来又不太直观,这里列举一下

 

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

 

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可以作为类方法暴露
来测试了:

 

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

 

分享到:
评论
3 楼 991142 2012-02-11  
解决我的疑问!
2 楼 fantaxy025025 2011-12-13  
非常感谢!我此处写的是错误的。

显式的调用类的私有方法,也是不行的。

但类的内部(也就是说隐式的调用)是可以的。我补充了一点。
Person.method4 #fantaxy added here! #NoMethodError: private method `method4' called for Person:Class

Thanks!
1 楼 ruby_windy 2011-12-13  
嗯,这个受限的终于弄清楚了,多谢.关于下面的表达,一点点疑问:


第一个问题,显式self不可以调用private(protected的也一样)方法,而隐式的可以 (这个原因我在下面解释) 。
原因是什么?
Ruby代码 
self.my_secret # => 显式 
#这一句的self在实例方法内,所以self指的是Person的一个实例,而实例是不能调用私有方法的(protected也如此) 
#注意,此时的self和我们new一个Person的实例没有本质区别。 

    第二个问题,self的方法不受private限制,其实我在这故意误导了读者,因为self的方法是类方法,而权限修饰符只对实例方法生效(下面解释) ,所以 private的类方法也可以直接访问。 // 这个意思是, private修饰的实例方法不受限,而类方法受限吧?

相关推荐

    Ruby语言详解(文档)

    Ruby语言详解(文档) 仅供学习交流! 后续会持续分享相关资源,记得关注哦! Ruby语言详解(文档) 仅供学习交流! 后续会持续分享相关资源,记得关注哦! Ruby语言详解(文档) 仅供学习交流! 后续会持续分享...

    Windows上配置Ruby运行环境详解

    在Windows操作系统上配置Ruby运行环境是一项重要的步骤,尤其对于开发者来说,这将使得你能够运行Ruby程序和使用相关的开发工具。Ruby是一种动态、面向对象的脚本语言,它以其简洁的语法和强大的元编程能力而受到...

    Ruby编程语言详解(内容丰富)

    - **特点**: Ruby的设计理念之一就是让代码尽可能简洁易读。这一点体现在其简洁的语法上,比如无需分号结束语句,以及使用`begin...end`或者直接用`do...end`来代替大括号 `{}` 来定义代码块。 - **示例**: `puts ...

    ruby-debug命令详解

    本文将详细介绍`ruby-debug`的使用方法和核心特性。 ### 一、安装`ruby-debug` 首先,为了使用`ruby-debug`,你需要确保你的系统已经安装了`ruby`, `rubygems`和`debugger` gem。你可以通过以下命令来安装: ```...

    Ruby语言教程知识点详解 ruby重点知识点总结掌握.docx

    Ruby语言教程知识点详解重点总结 章节目录 1.Ruby语言简介与安装 2.Ruby基础语法 3.数据类型与变量 4.运算符与表达式 5.控制结构 6.函数与模块 7.类与对象 8.继承与多态 9.异常处理 10.文件与I/O操作 11.Ruby标准库...

    Ruby.Programming_向Ruby之父学程序设计(第2版)

    《Ruby Programming:向Ruby之父学程序设计(第2版)》是为了让完全没有程序设计经验的读者也能灵活地使用Ruby,因此书中详细地说明了各种知识。从程序所需要的变量、常数、方法、类、控制结构等语法的说明,到类的主要...

    Ruby self在不同环境的含义

    而由于ruby作为一个完全纯净的面向对象语言,任何东东都是对象,方法是对象,类也是对象…,所以self就会有很多环境,区分不同环境的self含义才能更好的理解程序的含义 一、Top Level Context Ruby代码 puts self ...

    Ruby详解及安装流程,Ruby是一种高级编程语言,具有简单易学、灵活多变、优雅美丽的语法特点.md

    #### 一、Ruby详解 Ruby是一种高级编程语言,以其简单易学、灵活多变以及优雅的语法而闻名。作为一种面向对象的语言,Ruby支持动态类型和解释执行,使得开发者能够轻松地编写出清晰且具有高可读性的代码。以下是...

    详解Ruby当中的算数运算

    并行赋值是Ruby的一个独特特性,允许同时为多个变量赋值。如`a, b, c = 10, 20, 30`,一次性将10赋给a,20赋给b,30赋给c。此外,也可以用于变量的交换,如`a, b = b, a`。 位运算符在Ruby中处理二进制级别的数据,...

    如何利用Ruby简单模拟Lambda演算详解

    标题中的“如何利用Ruby简单模拟Lambda演算详解”是指通过Ruby编程语言来理解和实现Lambda演算的基本概念。Lambda演算是一个理论计算模型,它只包含函数定义和变量替换两个基本操作,却能表达所有可计算的功能。Ruby...

    《Ruby Programming—向Ruby之父学程序设计(第2版)》电子书

    总的来说,《Ruby Programming—向Ruby之父学程序设计(第2版)》是一本全面的教程,旨在引导读者从零基础逐步掌握Ruby编程,无论你是想成为一名全栈Web开发者,还是对编程充满好奇,这本书都将为你提供坚实的起点。...

    ruby对excel的操作 详细操作

    以下是关于如何使用Ruby操作Excel的详细步骤和知识点: 1. **引入win32ole库** 首先,你需要在Ruby脚本的开头引入`win32ole`库。这行代码`require 'win32ole'`使得Ruby程序能够调用Excel的API。 2. **启动Excel...

    R和Ruby数据分析之旅,中文完整扫描版

    如果你对万事万物的运行方式充满好奇,这本有趣的《R和Ruby数据分析之旅》会帮你找到日常生活中某些问题的真正答案。借助基本的数学方法,并使用Ruby和R语言做一些简单的编程工作,你就能学会如何对问题建模,并找出...

    [转] ruby学习一个综合小练习

    标题中的“ruby学习一个综合小练习”表明这是一个关于Ruby编程语言的学习资源,可能是通过一个实际的小项目或练习来帮助学习者提升对Ruby的理解。描述中提到的“博文链接”指向了一个特定的博客文章,虽然没有给出...

    R和Ruby数据分析之旅

    R和Ruby数据分析之旅 数据分析 数据挖掘

    ruby on Rails程序设计深入剖析与范例应用(pdf+视频+源码)

    ruby on Rails程序设计深入剖析与范例应用(pdf+视频+源码)

    Ruby.Programming_向Ruby之父学程序设计(第2版).pdf (含书签)

    [Ruby.Programming_向Ruby之父学程序设计(第2版)].(日)高桥征义,(日)后藤裕藏.扫描版(ED2000.COM).pdf ) 带书签

    Ruby_向ruby之父学程序设计(第二版)(经典入门)

    完整书名《Ruby Programming-向Ruby之父学程序设计》 ,就是那本经典的绿皮书 第一部分:通过简单的Ruby程序来介绍程序的基本架构。  第二部分:介绍基础语法规则,以及类、模块等面向对象程序设计的思考方法与...

    Ruby Ruby Ruby Ruby Ruby Ruby

    Ruby Ruby Ruby Ruby Ruby Ruby

Global site tag (gtag.js) - Google Analytics