- 类
- 方法
- 代码块
- 类宏
- Eval方法
实例变量、方法、类
实例变量(Instance Variables)是当你使用它们时,才会被建立的对象。因此,即使是同一个类的实例,也可以有不同的实例变量。
从技术层面上来看,一个对象(实例)只是存储了它的实例变量和其所属类的引用。因此,一个对象的实例变量仅存在于对象中,方法(我们称之为实例方法(Instance Methods))则存在于对象所属的类中。这也就是为什么同一个类的实例都共享类中的方法,却不能共享实例变量的原因了。
类
- 类也是对象。
- 因为类也是一个对象,能应用于对象的皆可运用于类。类和任何对象一样,有它们自己的类,Class类即是Class类的实例。
- 与其它的对象一样,类也有方法。对象的方法即是其所属类的实例方法。亦即,任何一个类的方法就是Class类的实例方法。
- 所有的类有共同的祖先Object类(都是从Object类直接或间接继承而来),而Object类又继承自BasicObject类,Ruby类的根本。
- 类名是常量(Constant)。
n = Class.new
puts n.ancestors
puts n.supperclass
puts n.supperclass.supperclass
puts n.supperclass.supperclass.supperclass
打开类
其实这个就跟方法重定义是一样的结果,不过随意改动可能会产生严重的后果,比如说你改的这个方法在其它地方有使用到,所以这种方法还是慎用,除非你非常明确该方法不会造成其它后果。
puts 'abc'.replace('a') # a
class String
def replace(string)
puts '重新打开了类'
end
end
'abc'.replace('a') #'重新打开了类'
我们也可以使用细化
来实现这个过程
细化
module StringExtensions
refine String do
def replace(string)
puts '细化'
end
end
end
在需要使用这个方法的地方使用using
如:using StringExtensions
细化的好处就是不会全局影响,在你需要使用的地方using就可以了,风险相对较小。
调用方法
类中的方法是怎么调用的?
- 方法的查找(接收者和祖先链)
Ruby中要在类中查找一个方法,首先在它的类查找这个方法,如果没有,则往上查找,如此类推,直到祖先链的顶端,到最后,如果还没找到,会抛出method_missing异常。如果有了解过JS,那么你肯定非常明白这个过程,因为JS中的方法查找也是类似于这个过程。 - 执行方法
在执行方法的过程中,Ruby始终需要一个接收者的引用,也就是self
self关键字
任何时刻,Ruby中只有一个对象能充当当前对象,并且没有哪个对象能长期充当这个角色,调用一个方法时,接收者就成为了self,从这一刻起,所有的实例变量都是self的实例变量,所有没有明确指明接收者的方法都在self上调用。
举个栗子:
class Book
def get_library
@book_count = 1000
self
end
def self.is_my_book?(book)
false
end
end
b = Book.new
b.get_library # 这个时候,b就充当了self
b.is_my_book?('Ruby元编程') # undefined method `is_book?' for #<Book:0x00000002b92268 @library=1000> (NoMethodError)
Book.is_my_book?('Ruby元编程') # false
上面调用is_my_book?的方法为什么会报错?
那是因为 self.is_my_book?(book)
等于 Book.is_my_book?(book)
当b调用的时候,self引用b实例对象,不等于Book,所以就会抛出找不到方法的错误
方法
- 动态派发(调用方法:对象.send(方法名,参数))
class Book
def create_book
'Ruby元编程'
end
def update_book
'Ruby元编程'
end
def delete_book
'Ruby元编程'
end
def search_book
'Ruby元编程'
end
end
s = Book.new
puts s.send(:get_one_name)
puts s.send(:get_two_name)
puts s.send(:get_three_name)
puts s.send(:get_four_name)
- 动态定义
class Book
['create', 'update', 'delete', 'search'].each do |item|
define_method("#{item}_book"){
puts "#{item}-Ruby元编程"
}
end
end
b = Book.new
b.create_book # create-Ruby元编程
b.update_book # update-Ruby元编程
b.delete_book # delete-Ruby元编程
b.search_book # search-Ruby元编程
- method_missing(幽灵方法)
# encoding: utf-8
class Book
def method_missing(name, *argc)
if [:create_book, :update_book, :delete_book, :search_book].include?(name)
puts "#{name}-Ruby元编程"
else
super
end
end
end
b = Book.new
b.create_book# create-Ruby元编程
b.update_book# update-Ruby元编程
b.delete_book # delete-Ruby元编程
b.search_book# search-Ruby元编程
b.book # undefined method `book'
代码块
...
类宏
如果按照以前的做法,定义一个属性的读写必须将每个属性定义一个Get 和 Set方法,比如如下代码
class Post
def title=(title)
@title = title
end
def title
@title
end
....
....
如果像一篇文章这样,定义title,content,author等属性,就需要写3组这样的方法,非常不方便。这个时候,就要亮出Ruby的类宏attr_accessor
(module的类里面的一个C语言写的方法,附上超链接,以上代码就可以写成
class Post
attr_accessor :title
end