“self”关键字在此 Class 方法中究竟在做什么?

What is the 'self' keyword doing exactly in this Class method?

提问人:BuiltByDan 提问时间:3/31/2022 更新时间:3/31/2022 访问量:392

问:

  class Restaurant

  attr_accessor :average_rating, :city

  def initialize(city, name)
    @city = city
    @name = name
    @number_of_ratings = 0
    @sum_of_ratings = 0
  end

  def rate(new_rate)
    @number_of_ratings += 1
    @sum_of_ratings += new_rate
    @average_rating = @sum_of_ratings.to_f / @number_of_ratings
  end

  def self.filter_by_city(restaurants, city)
    restaurants.select { |restaurant| restaurant.city == city }
  end
end

上面的代码是挑战的一部分,我一直没有通过#filter_by_city方法的测试。我检查了解决方案,唯一的区别是方法名称之前。我试图理解到底是什么,但如果没有上下文,就很难理解。在这个特定的类方法中,到底在做什么?我知道该方法的主体在做什么,即按城市过滤餐厅,但它究竟是如何运行的?self.selfself

Ruby-on-Rails Ruby 方法 self

评论

0赞 Jared Menard 3/31/2022
阅读此:Dzenspider.com/ruby/quickref.html 此外,“def self.my_function”声明一个类函数,而“def my_function”声明一个实例函数。第一个可以这样称呼:MyClass.my_function。第二个可以这样称呼:MyClass.new().my_function。一个是静态方法,一个是实例方法。
0赞 Jared Menard 3/31/2022
另外,请参阅此问题:stackoverflow.com/questions/34429693/...
0赞 user1934428 3/31/2022
#filter_by_city方法的测试一直不及格:你没有向我们展示你实际上是如何打电话的,所以我不能说你做错了什么。filter_by_city
0赞 Stefan 3/31/2022
self.是使它成为类方法的原因。没有它,将是一个实例方法。因此,询问类方法中正在做什么在某种程度上就像询问作业中正在做什么:-)self.self=

答:

4赞 Schwern 3/31/2022 #1

self是类。 是如何在类本身而不是类的实例上实现方法。 而不是 .Restaurantdef self.methodRestaurant.filter_by_city(...)Restaurant.new.filter_by_city(...)

selfRuby 中的更改取决于上下文。在方法中,是调用该方法的对象。self

在块内和任何方法之外,都是作为 Class 对象的对象。在 Ruby 中,一切都是一个对象。万事。class RestaurantselfRestaurant

您也可以通过声明一个块来执行此操作,其中类是实例。

class << self
  def filter_by_city(restaurants, city)
    restaurants.select { |restaurant| restaurant.city == city }
  end
end

通常,如果您有很多类方法,则会使用此语法。

有关更多信息,请参见 Ruby 中的 Self:全面概述

评论

0赞 BuiltByDan 3/31/2022
感谢您的回答和链接 - 非常有帮助。因此,在这种情况下,与我可以作为实例调用的方法 #rate 不同,即 check = Restaurant.new(..), check.rate,我假设我不能对 #self.filter_by_city 方法做同样的事情?如果是这样的话,为什么要让它成为自我。我什么时候可以将其设为私有?
0赞 Stefan 3/31/2022
相反,你也可以写(或想到)这与你调用此类方法的方式非常相似。def self.filter_by_citydef Restaurant.filter_by_city
0赞 Schwern 4/1/2022
@Stefan 是的,但不要这样写;如果类名更改或将方法提取到其他类或模块,它将中断。
0赞 Schwern 4/1/2022
@BuiltByDan Private 完全是另一回事。不能在声明私有方法的类之外调用私有方法。此方法旨在由 Restaurant 类的用户调用。它们传入一个 Array(或任何可枚举的)餐厅和一个城市,并且它只返回该城市中的那些餐厅。这个特定的方法有点傻,代码是微不足道的,但有时你会这样做来隐藏实现细节。
2赞 BroiSatse 3/31/2022 #2

在 ruby 中定义方法时,您可以选择使用语法而不是普通语法显式定义该方法的接收器def <receiver>.<method>def <method>

object = Object.new

def object.foo
  :foo
end

object.foo #=> foo

接收器必须是单数引用或表达式(但必须用括号括起来):

a = [Object.new, Object.new]

def (a.first).foo
  :foo
end

def (a[1]).bar
  :bar
end

a[0].foo #=> :foo
a.last.bar #=> :bar
a.first.bar #=> undefined method

定义 receiver 时,该方法将直接在接收器的单例类上定义,而忽略定义方法的上下文:

class A
  o = Obejct.new
  
  def o.foo
  end
end

A.new.foo #=> undefined method

即使方法 foo 是在类 A 体中定义的,但由于显式接收器,它对其实例不可用

self是返回当前“上下文”的 ruby 关键字。在方法内部,(通常)是调用的接收器,模块内部返回该模块。所以:selfself

module Wrapper
  module SomeModule
    puts self.name
  end
end

将打印 。Wrapper::SomeModule

这意味着:

class A
  def self.foo
  end
end

与以下内容完全相同:

class A
  def A.foo
  end
end

因此,该方法是直接在 上定义的,并且只能直接在类上调用,而不是在其实例上调用。AA.foo

评论

0赞 Stefan 3/31/2022
在后一个示例中,您甚至可以移动到类主体之外。顺便说一句,你说的“单数参考”是什么意思?def A.foo
0赞 Schwern 4/1/2022
这太疯狂了,我不知道接收器可以表达!另外:不要在实际代码中这样做。