首页  >  问答  >  正文

Ruby的class中定义以self.开头的方法有何不同

比如这个代码

class Category < ActiveRecord::Base
...

  def self.last_updated_at
    order('updated_at desc').limit(1).pluck(:updated_at).first.to_i
  end

...
end

为什么不直接定义last_updated_at方法呢?

高洛峰高洛峰2761 天前650

全部回复(3)我来回复

  • PHP中文网

    PHP中文网2017-04-22 09:01:47

    self 指向当前 class,所以这种定义方法会定义出 class 方法(class method),如果不加 self. 就会定义出实例方法(instance method)。

    这种 self. 的写法在你的例子里等同于:

      def Category.last_updated_at
        ...
      end
    

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-22 09:01:47

    一个ruby对象可以调用的方法有两类。
    一类是定义于该对象的class中,叫instance method,比如

    def last_updated_at
        #blahblah
    end
    

    那么Category的实例便可以调用该方法,而Category本身不可以

    category1=Category.new
    category2=Category.new
    category1.last_updated_at    #legal
    category2.last_updated_at    #legal
    Category.last_updated_at    #illegal
    

    另一类叫singleton method,它只能被一个对象调用,该对象的类不可以,与该对象同属一个类的其他对象也不可以。singleton method的定义方式如下

    #category1=Category.new
    def category1.last_updated_at
        #blahblah
    end
    

    这样定义之后,只有category1这个对象才可以调用last_updated_at方法

    category1.last_updated_at    #legal
    category2=Category.new
    category2.last_updated_at    #illegal
    Category.last_updated_at    #illegal
    

    ruby的类也是对象,也可以定义它自己的singleton method,比如

    def Category.last_udpated_at
        #blahblah
    end
    

    这样一来只有Category可以调用last_updated_at方法,而它的实例不可以,其他类也不可以,确切说任何其他对象都不可以

    Category.last_updated_at    #legal
    category=Category.new
    category.last_updated_at    #illegal
    

    在Category类的定义内部(方法的外部),self指代Category本身,故而

    def Category.last_udpated_at
        #blahblah
    end
    

    可以替换成

    def self.last_udpated_at
        #blahblah
    end
    

    这便是你问题中定义的那个方法。现在明白了吧?实质上它是Category的singleton method,而Category是一个类,类的singleton method又称为该类的class method,只能由该类本身调用。

    需要注意的是,class method就是singleton method,只不过它是一个类的singleton method,除此之外并没有什么特别之处。就像instance method由对象所属的class持有,singleton method也由对象的一个叫eigenclass的东西持有。关于eigenclass还有很多学问,这里就不提了。我会在文章里讲一下。

    回复
    0
  • 迷茫

    迷茫2017-04-22 09:01:47

    加self定义类方法,不加是实例方法

    定义类方法也可以是

    class << self
        def last_updated_at
        order('updated_at desc').limit(1).pluck(:updated_at).first.to_i
      end
    end
    

    回复
    0
  • 取消回复