介绍几种不常见的类定义方法:
1. Struct
Person=Struct.new(:name,:age,:sex)
p=Person.new("liyuchun")
puts p
Struct生成一个仅仅包含数据属性的类。但是你可以在这个类的基础上扩展:
Person=Struct.new(:name,:age,:sex)
class Person
def log
puts "log here"
end
end
ok,这样看上去并不是那么的cool,不是嘛。让我们稍微改一下:
class Person < Struct.new(:name,:age,:sex)
def log
puts "log here"
end
end
it seems better. "<" 只要求后面跟着任何返回一个class object的表达式即可。
2. Class.new
我们是怎么定义一个类的?
class A
end
a = A.new
追根溯源,A是一个Class类的对象,而a是A类的对象。既然A通过new方法可以生成a,那么是否可以Class也可以通过new方法生成A呢?of course.
A = Class.new do
def self.log
puts "log here"
end
def log
puts "log there"
end
end
a=A.new
A.log
a.log
By default,新生成的类会继承自Object。But,if I want to change? Still easy :
A = Class.new(String) do ... end
此时,A就是继承自String类。
3. instance_eval和class_eval
何以解忧?唯有看代码。
class MyClass
end
MyClass.class_eval do
def instance_method
puts "In an instance method"
end
end
obj = MyClass.new
obj.instance_method
然后
class MyClass
end
MyClass.instance_eval do
def class_method
puts "In a class method"
end
end
MyClass.class_method
class_eval生成的是实例方法,instance_eval生成的是类方法,何须多言啊,呵呵。
also,
animal = "cat"
"dog".instance_exec(animal) do |other|
puts "#{other} and #{self}"
end
Ruby 1.9 引进了一些变种. Object#instance_exec, Module#class_exec和Module#module_exec使用instance_exec,你可以将参数传入block。
ok,我们可以利用class_eval实现attr_accessor的功能了:
module Mod
def attr_reader1(*syms)
syms.each do |sym|
class_eval %{
def #{sym}
@#{sym}
end}
end
end
end
class A
extend Mod
attr_reader1 :name
def initialize
@name = "jinbin"
end
end
a=A.new
puts a.name
原来这里用的是include Mod,是不正确的。但是恰巧命名的函数为attr_reader,结果程序竟然也能运行通过,呵呵。ATTENTION!
这里使用了class_eval函数,出于对比,也用instance_eval来写了一个:
module Mod
def attr_reader(*syms)
syms.each do |sym|
instance_eval %{
def #{sym}
@#{sym}
end}
end
end
end
class A
extend Mod
attr_reader :name
@name = "jinbin"
def initialize
end
end
puts A.name
由于class_eval生成的是实例方法,instance_eval生成的是类方法,所以调用上有所区别,在代码中都有体现。此处可以细细深究一下,注意self的值。