ruby元编程 第二章 对象模型

2.1 打开类
class D
  def x; 'x'; end
end

class D
  def y; 'y'; end
end

obj = D.new
obj.x  # => "x"
obj.y  # => "y"	

当第一次提及 class D时,Ruby开始定义这个类,并定义x方法。
第二次提及D类时,它已经存在,Ruby就不在定义了,而只是重新打开这个已经存在的类,并为之定义y方法

ruby的class关键字更像是一个作用域操作符,而不是类型声明语句。

打开类的阴暗面:
如果粗心地为某个类添加了新功能,就可能无意中覆盖了原有的功能,这种方式称之为猴子补丁

2.2 类的真相
实例变量
class MyClass
  def my_method
    @v = 1
  end
end

obj = MyClass.new
obj.instance_variables # => []

obj.my_method
obj.instance_variables # => [:@v]

与java这样的静态语言不同,ruby中对象的类和它的实例变量没有关系
可以把ruby中实例变量的名字和值理解为哈希表中的键值对,每一个对象的键值对都可能不同

方法
obj.methods.grep(/my/) # => [:my_method]

String.instance_methods == "abc".methods # => true

String.methods == "abc".methods # => false

一个对象的实例变量存在于对象本身之中,而一个对象的方法存在于对象自身的类中。

类本身也是对象
"hello".class # => String
String.class # => Class

类像其他对象一样,也有自己的类,它的名字叫Class

ruby的类继承自它的超类

Array.superclass # => Object

Object.superclass # => BasicObject

BasicObject.superclass # => nil

Class.superclass  # => Module

Array类继承自object类, 换句话说, “数组是对象”

Object类中有大多数对象都需要的方法,比如 to_s方法

BasicObject是ruby对象体系中的根节点

Class类的超类是module, 也就是说每一个类都是一个模块。准确的说,类就是带有三个方法(new、allocate、superclass)的增强模块

#false表示忽略继承的方法
Class.instance_methods(false) # => [:new, :allocate, :superclass]

类与模块太接近了,保留这个概念的主要原因是为了获得代码的清晰性,让代码的意图更加明确

如果你希望吧自己的代码包含到别的代码中,就应该使用模块;如果你希望某段代码被实例化或者被继承,就应该使用类

类不过是对象而已,类名也无非就是常量

2.3 常量

任何以大写字母开头的引用(包括类名和模块名)都是常量
ruby中常量类似于变量,你可以修改常量的值。甚至可以修改String的类名

常量和变量最大的区别在于它们的作用域不同

module MyModule
  MyConstant = 'Outer constant'

  class MyClass
    MyConstant = 'Inner constant'
  end
end

MyModule::MyConstant # => "Outer constant"
MyModule::MyClass::MyConstant # => "Inner constant"

模块和类就像是目录,而常量则像是文件。像文件系统一样,只要不在同一个目录下,不同文件可以有相同的文件名。我们也可以像文件系统一样用路径来引用一个常量

Rake是流行的ruby构建系统 它的最初版本定义了一些常见的类名,例如Task和FileTask

这些类名与其他类库中的类名相冲突的概率很大,为了防止命名冲突,最近的Rake版本中把类定义在名为Rake的模块中

module Rake
  class Task
    #.....

像Rake这样只是用来充当常量容器的模块,被称为命名空间

2.4调用方法时发生了什么
Kernel模块

Ruby 中有一些方法(如print)可以随时调用。
这些方法实际上都是Kernel模块的私有实例方法
Object类包含了Kernel模块

self关键字

当前对象可以用self表示

class MyClass
  def test_self
    @var = 10
    my_method()
    self
  end

  def my_method
    @var = @var + 1
  end
end

obj = MyClass.new
obj.test_self # => #<MyClass:0x00007fa73508b950 @var=11>
private关键字

私有方法服从一条简单的规则:不能明确指定接受者来调用私有方法

class C
  def public_method
    self.private_method
  end

  private
  
  def private_method; end
end

C.new.public_method # => private method `private_method' called for #<C:0x00007fa5178d7e08> (NoMethodError)

去掉self关键字就能运行

私有方法只能通过隐形的接受者调用。
你只能在自身中调用私有方法

另外,可以调用从超类中继承来的私有方法,因为调用继承来的方法不用明确指明接受者

细化
module StringExtensions
  refine String do
    def reverse
      "esrever"
    end
  end
end

module StringStuff
  using StringExtensions
  "my_string".reverse # => "esrever"
end

"my_string".reverse # => ""gnirts_ym""

代码为String类细化了一个reverse方法,与打开类不同,细化在默认情况下并不生效,为了使其生效,必须调用using方法

从ruby2.1开始,你可以在一个模块内部调用using,这样,细化的作用范围只在该模块内部有效

细化只在两种场合有效:
1.refine代码块内部
2.从using语句的位置开始到模块结束,或者到文件结束(如果是在顶层上下文中调用using)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值