如果self指向ruby中的klassobject,为什么在ActiveRecord中将其用作赋值?

If self points to the klass object in ruby, why is it used as assignment in ActiveRecord?

注意:这是我能想到的最好的标题,它不会让这个问题看起来像一个骗局。如果没有抓住问题的要点,请随时编辑

所以我一直在阅读 Advanced Rails 并且我有一个问题没有被这些帖子完全回答:

在我的理解中,在class定义中,self指的是指针klass引用的object,所以对于[=34]的例子=]:

class A
  class << self
    def to.s
      "Woot"
    end
  end 
end

与:

完全相同
class << A
  def to.s
    "Woot"
  end
end 

这是因为当您打开 class 时,ruby 正在创建 Class:A (virtual) class 并分配 Aklass 指向它的指针。据我了解,这意味着在此 class 定义的上下文中 self == A

我的问题是(假设我在上面描述的理解是准确的)为什么在 ActiveRecord::Base subclass in Rails 中使用 self 似乎只是 instance 而不是 class 本身的消歧?

例如,如果我有一个 class: A < ActiveRecord::Base 和属性 name,我不能在 class 定义之外调用 A.name = "blah"。但是,我可以在 class 定义中的赋值中使用(并且实际上必须使用)self,如下所示:self.name = "blah"

如果在 Ruby 中使用 self 指的是 Class object 而不是 instance,为什么这在 ActiveRecord 中起作用以及如何Rails 有区别吗?

一切都是方法

你对对象所做的任何事情都是一种方法。当你有这样的 class 时:

class A
  attr_accessor :foo
end

obj = A.new
obj.foo = 3
obj.foo #=> 3

感觉有点奇怪,你这里没有赋值。 obj.foo = 3 只是 obj.send(:foo=, 3) 的合成糖,所以实际上它执行了 foo= 方法。 obj.foo 也是一种方法,它只是 returns 一个值。这是因为所有实例变量都是私有的,除了在方法内部没有其他方式可以与它们交互。 attr_accessor :foo 只是一个快捷方式:

def foo=(value)
  @foo = value
end

def foo
  @foo
end

现在,当 ruby 看到任何像 foo 这样的标识符时,它需要找出它是什么。首先,它假设它是一个局部变量,如果不是,它会尝试将它作为当前 self 上的方法执行(见下文)。这意味着:

class A
  attr_accessor :foo

  def bar
    foo = 'bar'
  end
end

a = A.new
a.bar   #=> 'bar'
a.foo   #=> nil

发生了什么事?解释器首先使用 foo 作为实例变量,它没有被定义。但是它旁边有一个赋值,所以它定义了一个新的实例变量并进行了赋值。如果我们想使用我们的 setter 我们需要告诉解释器它不是一个实例变量:

class A
  attr_accessor :foo

  def bar
    self.foo = 'bar'
  end
end

a = A.new
a.bar   #=> 'bar'
a.foo   #=> 'bar'

我撒谎了。万物皆对象

关于自己

ruby 中的

self 与 javascript 中的 this 非常相似 - 它在不同的上下文中表示不同的意思,并且可以随时轻松更改(显然,不推荐)。

首先你要知道在Ruby中每个class都是一个对象,即它是classClass的一个实例。当你这样做时

class A

它(几乎,下面的方法使用块并可以访问外部范围)等同于:

A = Class.new

self 在 class 的上下文中始终是 class 本身。

class A
  self #=> A

  def self.bar     #=> this is class method
    self #=> A
  end

  def foo      #=> this is instance method
    # We are no longer in context of class, but in context of the instance, hence
    self #=> instance of A
  end
end

现在,您可以为任何可变对象定义单例 class。这是一个奇怪的概念——它是原始 class 的一个额外子 class,只有一个实例。由于所有方法都来自 class,这允许您在方法的特定实例上定义额外的方法而不影响其他对象。在大多数情况下,实例 class 是不需要的,它是在您第一次访问它时创建的。有几种打开方式:

object.singleton_class do
  self #=> instance class
end

class << object
  self #=> instance class
end

您在实例 class 中定义的任何方法只能在该特定实例上访问,因此:

class A
  self #=> A
  class << A
    # we are now in the instance class of A (which is an instance of Class class)
    def foo
      # So this is an instance method, however our instance is a class A
      self #=> A
    end
end