【问题标题】:Why do we have implicit receiver in Ruby?为什么我们在 Ruby 中有隐式接收器?
【发布时间】:2017-06-04 14:12:08
【问题描述】:

我有两个关于 Ruby 核心 OOP 概念的问题。

  1. 我了解方法的显式调用(即使用 self)和隐式调用(即在实例方法中没有初始化的类对象或 self)之间的区别。当我们有显式接收器时,它们非常简洁明了地接收带有 self 的方法(因为它引用当前对象)而不是隐式接收器(我认为在何时使用同名方法或变量等情况下这是非常不确定的初始化),那为什么我们还要隐式调用方法呢?这只是一种偏好,还是因为正确使用私有和公共方法而有必要?

  2. 一般来说,OOP 私有方法绑定在类本身内部,不能在子类或外部访问。但是,那些需要私有但也需要在子类中访问的方法,然后在那里使用受保护的方法。但在 Ruby 中,私有和 受保护的方法在继承的类中被访问,唯一的区别是私有方法只能被隐式调用,而受保护的方法可以被隐式或显式调用。我不明白这里的哲学只是因为 ruby​​ 中的隐式调用功能,私有方法的一般定义不同?

【问题讨论】:

  • 对于 (1) - ruby​​ 社区不遵守“显式优于隐式”的原则。如果你缺乏上下文,你会看到不清楚的东西,但如果你有很好的理解,就会更简洁和“漂亮”(有人会说)。对于(2)-“一般 OOP”是什么意思?爪哇?我不记得上次在 ruby​​ 代码中看到 protected 方法是什么时候了。我同意这有点没用,但我不认为这是对私有和受保护的不太正确的解释。问问自己——为什么私有方法在子类中是不可访问的?
  • 感谢您的回答,但对于 (1) 我了解授权答案只能由 Matz 本人提供,因为我仍然不明白为什么有些东西虽然不清楚但很漂亮。
  • 对于 (2) 是的,我指的是 C# 和 Java。在我看来,私有方法是需要保护和封装的实现,它们仅在公共方法中使用,因此当父私有方法需要在子类中使用时,使用受保护的方法,我认为这是 Java、C# 中的基本目的,但是在 Ruby 中,它略有不同,那是因为隐式和显式接收器?很抱歉,我仍然不清楚您的第二个答案。
  • 对于 (1) - 您仍然可以在 java/c# 中调用没有显式接收器(又名this.)的方法。至于为什么self. 不“漂亮”——你一遍又一遍地重复自己。它很冗长。在正常的演讲中,你努力使用尽可能少的词来表达你的观点。与 js 不同,对于 self 在当前上下文中的含义,ruby 具有合理且易于遵循的规则。作为一名 ruby​​ist,您的目标受众是其他 ruby​​ist。因此self 是多余的。此外,如果总是需要显式接收器(如 python),那么 ruby​​ 就不能很好地编写 DSL。
  • 对于 (2) - 我只是不同意封装与向孩子隐藏私人事物有关。子类是其父类的进一步规范,而不是局外人。在Cow 的定义中,您仍然指的是Mammal。因此,如果您需要,您仍然应该能够推理哺乳动物的消化道,即使您最终提供的抽象是“物质进入,能量被吸收,物质流出”。

标签: ruby oop


【解决方案1】:

我认为您对受保护方法的目的略有误解。受保护的方法可以从同一类的另一个实例的方法中调用。

class Person

  def initialize(name, age)
    @name = name
    @age = age
  end

  def older_than?(other_person)
    age > other_person.age
  end

  protected

  def age
    @age
  end

end

mother = Person.new('Carole', 34)
father = Person.new('George', 37)

如果你尝试...

mother.age
=>NoMethodError: protected method `age' called for #<Person:0x0000000327daa0 @name="Carole", @age=34>

所以你不能在外部调用#age 方法。

但你可以做...

father.older_than?(mother)
=> true

所以father对象能够调用mother对象#age方法,因为他是同一类Person的对象。

【讨论】:

    【解决方案2】:

    在下面的讨论中,回想一下,使用隐式接收器 (self) 调用实例方法的唯一方法是在同一类的实例方法中这样做。

    问题是为什么 Ruby 被设计为允许使用隐式接收器调用大多数1 实例方法。

    人们可能不得不要求 Matz 得到一个权威的答案,但我的猜测是它可以追溯到私有实例方法的实现方式。要求使用隐式接收器调用它们被认为(我猜)是一种简单的方法,可以防止它们从同一类的实例方法之外的任何地方调用。

    但是,如果必须使用隐式接收器调用私有方法,那么为了保持一致性,是否允许(几乎所有)公共和受保护的实例方法使用隐式接收器调用?

    一些 Rubiest 认为使用显式接收器 self 是多余的,因此使用隐式接收器(除非需要 self.)。其他人将隐式接收器的使用视为潜在的混淆来源,因此使用self.,知道(或可能不知道),这是可选的。据我所知,Ruby 中实现的所有核心 Ruby 方法都使用隐式接收器。第一阵营的人可能会争辩说,多余地使用self. 类似于说“在蓝色的蓝墙上见我”。

    1 在少数情况下,需要显式接收者self 以避免歧义。最常见的两种情况是调用方法 class(考虑到 class 也是一个关键字)和调用 setter,否则 Ruby 可能会将其与为新创建的局部变量赋值混淆。另一个例子是我们不能写Array 方法def a; [1]; end 也不能写def a; [](1); end。同样,需要一个明确的接收者:self[1]self.[](1)

    【讨论】:

      猜你喜欢
      • 2013-05-09
      • 1970-01-01
      • 1970-01-01
      • 2021-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多