当我在IRB中声明顶级方法时,为什么我的顶级方法在所有类上都是公共的(而不是私有的)?

时间:2018-12-31 02:47:38

标签: ruby irb private-methods public-method

我当前正在阅读“ The Well-Grounded Rubyist”,在第196页上,我看到以下内容:

  

假设您在顶层定义了一个方法:

def talk
  puts "Hello"
end
     

....

     

您在顶层定义的方法存储为私有方法   Object类的实例方法。之前的代码是   等效于此:

class Object

  private

  def talk
    puts "Hello"
  end
end
     

...

     

为说明起见,让我们扩展talk示例。又来了   带有一些执行它的代码:

puts "Trying 'talk' with no receiver..."
talk
puts "Trying 'talk' with an explicit receiver..."
obj = Object.new
obj.talk
     

talk的第一次调用成功;第二个失败并致命   错误,因为它尝试使用显式调用私有方法   接收器。

我想在本地复制它,所以将上面的代码放在我创建的Ruby文件中。我确实得到了书中提到的结果:

$ ruby talk.rb 
Trying 'talk' with no receiver...
Hello
Trying 'talk' with an explicit receiver...
Traceback (most recent call last):
talk.rb:22:in `<main>': private method `talk' called for #<Object:0x00007f9a8499c3e0> (NoMethodError)

我还尝试了以下方法,产生了与通过Ruby解释器运行代码相同的错误:

irb(main):008:0> load 'talk.rb'
Trying 'talk' with no receiver...
Hello
Trying 'talk' with an explicit receiver...
Traceback (most recent call last):
        4: from /Users/richiethomas/.rbenv/versions/2.5.3/bin/irb:11:in `<main>'
        3: from (irb):8
        2: from (irb):8:in `load'
        1: from talk.rb:22:in `<top (required)>'
NoMethodError (private method `talk' called for #<Object:0x00007ffb219c95e0>)

接下来,我在irb中尝试了相同的代码,这次我得到了以下奇怪的结果:

irb(main):001:0> def talk
irb(main):002:1> puts "Hello"
irb(main):003:1> end
=> :talk
irb(main):004:0> puts "Trying 'talk' with no receiver..."
Trying 'talk' with no receiver...
=> nil
irb(main):005:0> talk
Hello
=> nil
irb(main):006:0> puts "Trying 'talk' with an explicit receiver..."
Trying 'talk' with an explicit receiver...
=> nil
irb(main):007:0> Object.new.talk
Hello
=> nil

如您所见,在上一个代码示例中,我能够调用Object.new.talk并将其打印为Hello,就像.talk是{{1}上的公共方法一样}实例。

我的问题是-为什么在我直接在REPL中实现Object方法时,它在Object类上是公共的,而当我在文件中实现并将其加载到REPL中时(以及当我通过Ruby解释器直接在我的CLI中运行该文件)?

1 个答案:

答案 0 :(得分:1)

irbpry边注:我强烈建议使用后者)调整其输入以将所有方法声明为公共方法(在 {{1 }} E循环的阶段):

REP

就是这样,没有魔术。


这样做的目的主要是为了简化在以下情况下的使用过程:当一个人在此处定义该方法,然后希望可以从例如那里。在▶ def foo; end #⇒ :foo ▶ public_methods.grep /foo/ #⇒ [:foo] 中,使所有地方都可以访问是值得的。

REPL

在玩沙盒时,不要太在意封装,SRP等。


通常,这就像使用通用助手声明该模块,并在所有地方免费包含它。