了解Ruby中的私有方法

nwsw7zdq  于 2023-01-25  发布在  Ruby
关注(0)|答案(8)|浏览(292)
class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.example_test

这当然不会起作用,因为我们指定了Example(e)的显式接收方示例,而这违反了“私有规则”。
但我不明白,为什么不能在鲁比中这样做:

class Foo
 def public_m
  self.private_m # <=
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

public_m方法定义中的当前对象(即self)是Foo的示例。那么为什么不允许这样做呢?为了解决这个问题,我必须将self.private_m更改为private_m。但是为什么这会不同呢?self不就是public_m里面的Foo的一个示例吗?那么谁是private_m裸字调用的接收者呢?那不就是self吗--实际上你忽略了什么,因为Ruby将为您执行此操作(将在self上调用private_m)?
我希望我没有混淆它太多,我仍然新鲜的Ruby。
编辑:谢谢你所有的答案。把它们放在一起,我终于能够(终于)摸索出显而易见的东西(对于从未见过Ruby这样的东西的人来说,就不那么明显了):self本身可以是显式和隐式的接收器,这就有区别了,所以有两个规则,如果你想调用一个私有方法:self必须是隐式接收器,并且self必须是当前类的示例(在这种情况下为Example-并且只有在self位于示例方法定义内时,在此方法执行期间才会发生)。如果我说错了,请更正。

class Example 

 # self as an explicit receiver (will throw an error)
 def explicit 
  self.some_private_method
 end

 # self as an implicit receiver (will be ok)
 def implicit
  some_private_method
 end

 private

 def some_private_method; end
end

Example.new.implicit

消息给任何人谁可以找到这个问题在谷歌步道:这可能会有帮助-http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

krugob8w

krugob8w1#

这里是它的简称和全称。在Ruby中,private的意思是一个方法不能被显式接收者调用,例如some_instance. private_method(value)。因此,尽管隐式接收者是self,但在示例中,您显式地使用了self,因此私有方法是不可访问的。
这样想一下,你希望能够使用一个你已经赋给类示例的变量来调用一个私有方法吗?不。Self是一个变量,所以它必须遵循同样的规则。然而,当你只是在示例中调用方法时,它会像预期的那样工作,因为你没有显式地声明接收器。
Ruby就是这样,你实际上可以使用instance_eval调用私有方法:

class Foo
  private
  def bar(value)
    puts "value = #{value}"
  end
end

f = Foo.new
begin
  f.bar("This won't work")
rescue Exception=>e
  puts "That didn't work: #{e}"
end
f.instance_eval{ bar("But this does") }

希望你说得更清楚一点。

  • 编辑-
    我猜你知道这会有用
class Foo
 def public_m
  private_m # Removed self.
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
gojuced7

gojuced72#

Ruby中private的 * 定义 * 是“只能在没有显式接收器的情况下调用”,这就是为什么你只能在没有显式接收器的情况下调用私有方法,没有其他解释。
请注意,这条规则实际上有一个例外:由于局部变量和方法调用之间的不明确性,以下内容 * 总是 * 被解析为对局部变量的赋值:

foo = :bar

那么,如果你想调用一个名为foo=的编写器,你应该怎么做呢?嗯,你必须添加一个显式的接收器,因为如果没有接收器,Ruby就不知道你想调用方法foo=,而不是赋值给本地变量foo

self.foo = :bar

但是如果你想调用一个名为foo=private编写器,你该怎么做呢?你 * 不能 * 写self.foo =,因为foo=private,因此不能用显式接收器调用。(仅在本例中),您实际上可以使用self的显式接收器来调用private编写器。

7kqas0il

7kqas0il3#

这很奇怪,但是Ruby的可见性修饰符的很多地方都很奇怪。即使self是隐式接收器,实际上拼写出来在Ruby运行时看来也是显式的。当它说私有方法不能用显式接收器调用时,这就是它的意思,即使self也算数。

eit6fx6z

eit6fx6z4#

IIRC,私有方法 * 只 * 允许隐式接收方(当然,总是self)。

11dmarpk

11dmarpk5#

抱歉,我的回答太唐突了。我不明白你的问题。
我这样修改了你的代码:

class Foo
 def public_m
  private_m # <=
 end

 def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

 private 
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m
Foo.static_m
Foo.static2_m

下面是示例方法的调用:

def public_m
  private_m # <=
 end

下面是调用类的方法:

def Foo.static_m
   puts "static"
 end

 def self.static2_m
   puts "static 2"
 end

Foo.static_m
Foo.static2_m
kyks70gy

kyks70gy6#

对用户门解决方案增加了一些增强。调用私有方法到类方法或示例方法是非常可能的。这里是代码片段。但不推荐。
类方法

class Example
  def public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.new.public_m

示例方法

class Example
  def self.public_m
    Example.new.send(:private_m)
  end

  private
  def private_m
    puts 'Hello'
  end
end

e = Example.public_m
vuktfyat

vuktfyat7#

没有确切回答Question,但可以通过这种方式调用私有方法

class Example
 private
 def example_test
  puts 'Hello'
 end
end

e = Example.new
e.send(:example_test)
hts6caw3

hts6caw38#

以防现在有人搞砸了,从Ruby 2.7开始,调用一个带有字面意义self作为接收方的私有方法是允许的。
我们也可以通过在2.6.9和3.1版本上运行原始的ruby代码片段来验证这一点。

(ins)tmp->cat sample.rb 
class Foo
 def public_m
  self.private_m # <=
 end
 private
 def private_m
  puts 'Hello'
 end
end

Foo.new.public_m

# See no exception is raise with 3.1 version
(ins)tmp->ruby -v
ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-darwin20]
(ins)tmp->ruby sample.rb 
Hello

现在,如果我们尝试在2.6.9版本中运行相同的脚本,我们会看到引发了异常。

(ins)tmp->ruby -v
ruby 2.6.9p207 (2021-11-24 revision 67954) [x86_64-darwin20]
(ins)tmp->
(ins)tmp->ruby sample.rb 
sample.rb:3:in `public_m': private method `private_m' called for #<Foo:0x00007ff95289f870> (NoMethodError)
Did you mean?  private_methods
        from sample.rb:11:in `<main>'

相关问题