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)