我什么时候需要单独使用 self.instance_method 与 instance_method?

When do I need to use self.instance_method vs instance_method alone?

我希望有人能解释为什么我从这两种方法中获得相同的行为,以及何时使用或不使用 self 意味着什么。

def my_instance_method(arg)
  'execute some code' if another_instance_method_of_same_class?(arg)
end

似乎与

的行为完全相同
def my_instance_method(arg)
  'execute some code' if self.another_instance_method_of_same_class?(arg)
end

如果我的搜索技巧没有达到标准,我深表歉意,但我找不到这个问题的确切答案,只是解释了 self 做了什么(这让我觉得我应该需要它)。 我正在使用 Ruby 的最新版本。谢谢。

self.foo(...)foo(...) 之间存在一些差异,但它们基本相同。

隐私

private 方法只能通过 foo 直接调用,而不能使用显式接收者。因此,如果 foo 被标记为 private,那么您 必须 调用它而无需 self

class Example

  private def foo(x)
    x + 1
  end

  def bar
    foo # Works fine
    self.foo # Error: foo is private
  end

end

阴影

如果您在当前函数中有一个名为 foo 的局部变量,那么在不带参数的情况下编写 foo 将改为引用局部变量

class Example

  def foo(*args)
    puts "Hello :)"
  end

  def bar
    foo = 100 # Just an ordinary variable; no relation to the above method
    foo # This refers to the local variable called "foo"
    self.foo # This calls the method foo() with no arguments
    foo(1) # This calls the method foo() with one argument
    self.foo(1) # Equivalent to the above; calls with one argument
  end

  def baz
    foo # There's no local variable called "foo", so this calls the method
  end

end

作业

如果您谈论的方法是赋值方法(即以 = 结尾),则必须始终使用显式接收者调用它

class Example

  def foo=(value)
    puts "Assigning foo = #{value}"
  end

  def bar
    foo = 0 # This creates a new local variable called foo and assigns to it
    self.foo = 0 # Calls foo= on self
  end

end

我会回答你的问题,但这并不能帮助你理解在定义方法时什么时候要使用前缀self.。因此,我需要首先介绍一些关于 实例方法 .

的背景信息

假设我们有以下 class 定义。

class C
  puts "self = #{self}

  def i
    puts "self in i = #{self}"
    "i"
  end

  def self.c
    puts "self in c = #{self}"
    "c"
  end

  singleton_class.define_method(:s) do
    puts "self in s = #{self}"
    "s"
  end
end
  #=> :s
  self = C

我定义了一个实例方法 C#i、一个 class 方法 C::c 和一个实例方法 C 单例 class、s.

请注意,由于self #=> C在class中,因此写def self.c ...def C.c ...完全相同。写 self 的唯一原因是如果我们重命名 class 我们不必更改 def self.c ... 和 “self”比“PhilharmonicOrchestras”更难拼错。

不出所料,

C.instance_methods(false)
  #=> [:i]
instance = C.new
  #=> #<C:0x00007ff0011074f0>
instance.i
  #=> "i"
  self in i = #<C:0x00007ff0011074f0>

现在考虑最后两种方法:

C.methods(false)
  #=> [:s, :c]
C.c
  #=> "c"
  self in c = C
C.singleton_class.instance_methods(false)
  #=> [:s, :c]
C.s
  #=> "s"
  self in s = C

这表明定义方法 def self.class.c 只是一种 shorthand 告诉 Ruby 您希望创建 实例方法 的方式sC 的单身人士 class 上。同样,对于那些相同的实例方法,对“class 方法”的引用是 shorthand。其实不需要定义前缀为self.的方法。您可以像我所做的那样使用 singleton_classdefine_method,或者选择其他几种方式之一,最常见的是

class C
  class << self
    def s
      puts "self in s = #{self}"
      "s"
    end
  end
end

其中 class << self .. end 导致 selfC 变为 C.singleton_class


你定义了一个方法,我会稍微修改一下:

self
  #=> main

def my_instance_method
  puts "self = #{self}, self.class = #{self.class}"
  'execute some code'
end
my_instance_method
  #=> "execute some code"
  self = main, self.class = Object

由于所有方法都是实例方法,所以这也必须是一个,即 Object:

的私有实例方法
Object.private_instance_methods.include?(:my_instance_method)
  #=> true

作为私有实例方法,我们不能在作为 Object (main) 实例的显式接收器上调用它,但我们可以这样写:

Object.new.send(:my_instance_method)
  #=> "execute some code"
  self = #<Object:0x00007f988514e180>, self.class = Object

请注意,如果它是一个 public 方法,它将可供所有对象使用,这显然会导致灾难。

接下来考虑:

def self.your_instance_method
  puts "self = #{self}, self.class = #{self.class}"
  'execute some code'
end
your_instance_method
  #=> "execute some code"
  self = main, self.class = Object

这个方法必须定义在self的(main的)单例class上,我们可以确认:

self.singleton_class.instance_methods.include?(:your_instance_method)
  #=> true

因此,

的隐含接收者
your_instance_method

self,等于 main,结果与

相同
self.send(:your_instance_method) 

这是一个复杂的主题(关于 Ruby 的 Object Model),特别是对于 Ruby 的新手来说,所以如果您无法理解,请不要担心按照我说的做。