Ruby中的单例方法、instance_eval和class_eval

816 阅读2分钟

在之前的文章里,我们讲述了 Ruby的基础语法Ruby和Cocoapods文章合集,今天我们来探讨下Ruby中的单例类

单例类

单例类定义被用于定义对象的专属示例方法:

str1 = "Ruby" # 1
str2 = "Ruby"

class << str1 # 2
    def hello
        "Hello, #{self}"
    end
end

p str1.hello  #=> "Hello, Ruby"
p str2.hello  #=> 错误 (NoMethodError)
  • 1,初始化了两个字符串的实例变量 str1str2
  • 2,给实例对象str1定义一个 hello方法。

通过调用输出结果我们可得,str1实例可以正常调用,而在 str2实例里面没有hello方法。

这样,我们就实现了只给一个实例对象,增加方法的目的。

我们来看下一个例子

class << String  #1
    def sayGood(str)
        "good, #{str}"
    end
end

p String.sayGood("ruby") # => "good, ruby"
  • 1,在Ruby中,所有的类都是 Class 类实例String类也是Class 类的实例,给String 类实例增加实例方法,就相当于给 String类增加类方法

如果只希望对某个实例添加方法时,就需要利用单例方法

instance_eval

instance_eval的官方解释如下:

截屏2021-09-14 下午8.36.49.png 它可以将字符串Ruby源代码的形式执行,或者执行传递过来的blcok。主要是用来使实例拥有访问变量私有方法的权限

首先,我们来看下如下代码

class B
end
b1 = B.new
b1.instance_eval do  # 1
    p self
    
    def method1 
        puts "this is a singleton method of instance b"
    end
end

b1.method1 # => this is a singleton method of instance b
b2 = B.new
b2.method1 # => error undefined method

输出结果:
#<B:0x00007fe43815f558> 
this is a singleton method of instance b

Uncaught exception: undefined method `method1' for #<B:0x00007fe43815f0f8> Did you mean? method methods
  • 1,b1对象,通过 instance_eval方法执行 block,增加了一个方法名为 method1单例方法b2实例是没有该方法的。此时的 selfb1实例变量#<B:0x00007fe43815f558>

前面我们提到过,Ruby中,都是 Class的实例,所以,对 我们也可以对使用instance_eval方法,就像相当于对该类增加了一个类方法

class W
end
W.instace_eval do
    p self
    def sayW
        p "say W......"
    end
end

W.sayW

w1 = W.new
w1.sayW

输出结果:
W 
"say W......"
Uncaught exception: undefined method `sayW' for #<W:0x00007faca110ff68>

类实例(类对象)增加了一个类方法 sayW,此时的self等于 W

class_eval

截屏2021-09-14 下午9.14.50.png

class_evalinstance_eval类似,它主要用来给一个类增加方法

class C
end

C.class_eval do
    def methodC1
         p self
         puts "methodC1......"
    end
    
    def self.methodC2
        p self
        puts "methodC2......."
    end
end
c = C.new
c.methodC1

C.methodC2
输出结果:

#<C:0x00007fc8ab2001b8> 
methodC1...... 
C 
methodC2......

class_eval在增加方法的时候,感觉和平时开发中定义方法是一样,给整个类增加实例方法和类方法