Ruby元编程-学习笔记(四)-类定义

本文详细介绍了Ruby中的类定义,包括当前类、class_eval()、类实例变量、类变量、单件方法、Eigenclass、类宏、方法别名以及环绕别名等概念。class_eval()在类上下文中执行代码,而单件方法只针对单个对象有效。Eigenclass是对象特有的隐藏类,用于存放对象的单件方法。Ruby的attr_*()方法家族提供了一种定义访问器的类宏方式,而alias关键字可以为方法创建别名。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类定义

在类或模块定义时,其自身充当了当前对象self的角色,类和模块也都是对象,与方法和块相同,类定义也会返回最后一条语句的值.

class MyClass
    puts "Hello"
end

=> Hello

当前类

尽管self可以获得当前对象,但并不能获得当前类,每当通过class关键字打开一个类时,这个类就成为当前类.

class MyClass
    # 现在当前类是MyClass
    def my_method
        # my_method是MyClass的一个实例方法
    end
end

class关键字必须指定类名才可以打开类,对于未知类名就可以修改当前类,可以使用class_eval().

class_eval()

Module#class_eval()方法会在一个已存在类的上下文中执行一个块.

def add_method_to(a_class)
    a_class.class_eval do
        def my_method do
            "Hello!"
        end
    end
end

add_method_to String
"str".my_method         # => "Hello!"

class_eval()方法与instance_eval()方法并不相同, instance_eval()方法仅会修改self(特定情况下也会修改当前类),而\calss_eval()方法会同时修改self和当前类.
对于二者的选择,若只想打开一个对象,并不在乎是不是类,使用instance_eval更好;而若是希望打开类,则使用class_eval()更好.

类实例变量

由于类是Class的实例,类名是常量,故而当self由当前类充当时所定义的变量即为类实例变量.

class MyClass
    @my_var = 1

    def self.read; @my_var; end    # self为当前类MyClass
    def write; @my_var = 2; end    # self为调用该方法的接收者
    def read; @my_var; end
end

obj = MyClass.new
obj.write
obj.read            # => 2
MyClass.read        # => 1

类变量

类变量与实例变量不同, 它们可以被子类或类的实例所引用, 类似java静态成员.

@@v = 1
class MyClass
    @@v = 2
end

@@v     # => 2

这种情况不就破坏了class域作用门的性质, 得到这种结果是因为类变量并不真正属于类,它们属于类体系结构, 由于@@v定义与man顶级作用域中,它属于main的类Object,所以也属于Object所有的后代,而MyClass继承自Object,因此也共享了这个类变量.

单件方法

Ruby允许给单个对象增加一个方法, 该方法只对这个对象有效,称为单件方法.

str1 = "abc"
str2 = "abc"

def str1.single_method
    "singleton_method!"
end
str1.class                  # => String
str1.single_method          # => "singleton_method!"
str2.class                  # => String
str2.single_method          # => Error:NoMethodError

从上述代码可以看出同样是String类对象的str1和str2, str1有single_method方法,而str2没有, 还记得前面讲过,对象保存的只是一组实例变量和它自身类的引用,对象的方法都保存在自身类中,很明显single_method方法并不在str2的祖先链中, 那么single_method方法去哪了?下面的Eigenclass则告诉了我们答案.

Eigenclass

在obj上定义一个单件方法, 它存放在哪, 同样类是Class的对象, 而类方法不能被类的实例对象调用,说明类方法不在Class中,那么又存放在哪里呢?
当一个对象索要它的类时,Ruby并没有告诉我们全部,我们得到的类并不是看到的类,而是一个对象特有的隐藏类,我们称之为eigenclass.

obj = Object.new
eigenclass = class << obj
    self    # => Class
end
def obj.my_singleton_method; end
eigenclass.instance_methods.grep(/my_/)  # => ["my_singleton_method"]

在查找方法时,会先从接收者的eigenclass中查找,若未找到,则在eigenclass的超类中查找.
一个对象的eigenclass的超类是这个对象的类;一个类的eigenclass的超类是这个类的超类的eigenclass.

module MyModule
    def self.my_method; 'hello'; end
end

class MyClass
    include MyModule
end

MyClass.my_method       # => Error: NoMethodError

当类包含模块时,它获得的是该模块的实例方法而不是类方法,类方法存在与模块的eigenclass中. 那么如何通过包含模块来定义类方法.

module MyModule
    def my_method; 'hello'; end    # 首先在模块中定义普通实例方法
end

class MyClass
    class << slef        # 通过打开MyClass的eigenclass来包含模块
        include MyModule
    end
end

MyClass.my_method       # => 'hello'

my_method()方法是MyClass的eigenclass的一个实例方法,这样my_method()也是MyClass的一个类方法,这种技术称为类扩展.同样该技术运用在对象中则是对象扩展.

类宏

在Java中要想访问一个类的私有属性需要get和set方法,虽然Ruby对象并没有属性,但如果想像get和set一样访问,就会定义两个拟态方法.

class MyClass
    def set=(value)
        @attr = value
    end
    def get
        @attr
    end
end

这样的写法会给人很枯燥的感觉,我们可以通过Module#attr_*()方法家族中的成员来定义访问器.Module#attr_reader()可以生成一个读方法, Module#attr_writer()可以生成一个写方法,Module#attr_accessor()可以同时生成两者.
所有的attr_*()方法都定义在Module中,所以不过self是类还是模块,都可以使用它们.类似与attr_accessor()的方法我们称之为类宏, 虽然类宏看起来像关键字,但它们只是普通方法,只是可以用在类定义中.

方法别名

通过使用alias关键字,可以给Ruby方法取一个别名.

class MyClass
    def my_method
        "my_method()"
    end
    alias :m :my_method  # 第一个是新名字
end

obj = MyClass.new
obj.my_method           # => "my_method()"
obj.m                   # => "my_method()"

环绕别名

class String
    alias :real_length :length

    def length
        real_length > 5 ? "long" : "short"
    edn
end

"This a test example".length        # => "long"
"This a test example".real_length   # => 20

上述代码虽然重写了length方法,但是别名方法还是引用的原始方法.
当重定义一个方法时,并没有真正修改这个方法,而是把当前存在的这个方法名与新定义的方法绑定起来, 只要旧方法还存在绑定的名字,仍然可以调用.旧的方法被新的方法所环绕,这种技巧称为环绕别名,步骤如下:.

1.给方法定义一个别名
2.重定义这个方法
3.在新的方法中调用老的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值