self 在初始化和其他 class 方法中使用时如何工作?

How self works when using it in the initialize and other class methods?

我正在学习 ruby,在这个例子中 self 的概念让我很困惑。

class Alpha
    def initialize
        self.A
    end

    def self.A
        puts "A"
    end 

    def self.B 
        self.A
        puts "B"
    end
end

当我尝试从 class Alpha

创建一个新实例时
Alpha.new

我得到了NoMethodError,但是当我调用B方法时,它正常执行。

Alpha.B
# A
# B
#=>nil

initialize 在实例上下文中运行,而不是在 class 上下文中运行。如果要调用class方法,则需要self.class.A。或者你可以尝试更疯狂地覆盖 class new 方法:

class Alpha
  def self.new
    self.A
    super # this actually calls initialize after object is created
  end

  [...]
end

首先定义class Alpha如下。

class Alpha
  puts "self in Alpha = #{self}"

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

  def Alpha.b
    puts "self in b = #{self}"
  end 

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

我们有一个实例方法 Alpha#a 和两个 class 方法,Alpha::bAlpha::b。 (以这种方式引用实例和 class 方法是一种 Ruby 约定,您将一直在文档中看到这一约定。)

Alpha.methods(false)
  #=> [:c, :b] 
Alpha.instance_methods(false)
  #=> [:a] 

参见 Object::methods and Module#instance_methods,注意包含参数 false 的含义。

在 class 的实例上调用实例方法; class 方法在 class.

上被调用
alpha = Alpha.new
  #=> #<Alpha:0x000059c5ff614f08> 
alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>

Alpha.b
  # self in b = Alpha
Alpha.c
  # self in c = Alpha

如果我们尝试调用 class 上的实例方法或实例上的 class 方法怎么办?

Alpha.a
  #=> NoMethodError (undefined method `a' for Alpha:Class)
alpha.b
  #=> NoMethodError (undefined method `b' for #<Alpha:0x000059c5ff614f08>)

我们通常会这样写class。

class Alpha
  def a
    puts "self in a = #{self}"
  end

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

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

在class定义中selfAlpha,这就是为什么class的两种写法是等价的。使用 self 的唯一原因是,如果我们稍后决定将 class 的名称更改为 Beta,我们将不必将所有 Alpha 的名称更改为Beta 在 class 方法定义中。

如果我们想从实例方法 Alpha#a 中调用 class 方法 Alpha::b 我们必须按如下方式更改后者:

class Alpha
  def a
    puts "self in a = #{self}"
    self.class.b
  end
end

alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>
  # self in b = Alpha

这里self.classreturnsAlpha,我们知道Alpha.breturns.

让我们再次更改Alpha#a并添加第二个实例方法:

class Alpha
  def a
    puts "self in a = #{self}"
    d
  end

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

alpha.a
  # self in a = #<Alpha:0x000059c5ff614f08>
  # self in d = #<Alpha:0x000059c5ff614f08>

我本可以写成:

  def a
    puts "self in a = #{self}"
    self.d
  end

self. 不是必需的,通常不包括在内。原因是当一个方法没有明确的接收者时,如d in:

def a
  puts "self in a = #{self}"
  d
end

self 成为 默认接收者 。我们从上面的讨论中知道,在实例方法定义中 self 等于实例 alpha.