【问题标题】:"k.send :hello" - if k is the "receiver", who is the sender?"k.send :hello" - 如果 k 是“接收者”,谁是发送者?
【发布时间】:2010-10-29 08:14:22
【问题描述】:

在下面的示例中,如果as stated elsewhere,k 实际上是接收者,为什么我们说“k.send :hello”而不是“k.receive :hello”?

听起来好像 k 是发送者而不是接收者。

当我们说“k.send :hello”时,谁在发送,如果不是 k?

(你和我一样困惑吗?)

class Klass
  def hello
    "Hello!"
  end
end
k = Klass.new
k.send :hello   #=> "Hello"
k.hello         #=> "Hello"

【问题讨论】:

    标签: ruby terminology


    【解决方案1】:

    在 Smalltalk 中,一切都是对象。 “发送者”是消息来源范围的所有者(即“this”或“self”指针)的对象。

    和以前一样,Ruby 继承了这个概念。用不太抽象的术语来说,如果我给你寄一封信,我是“发件人”(它来自我的办公室),而你是“收件人”(前面的地址是你的)。所以我会写 foo.send myLetter: 你,foo,收到我的信。发件人是隐含的,代码的所有者进行“发布”。

    【讨论】:

    • 嗯。还是真的很纠结这个。我来自Java。所以我在一个对象上“调用”一个方法。这与这个发送/接收概念不同还是只是不同的术语?
    • 只是术语不同:对于“呼叫”,请阅读“发送消息”。对于“我已被调用”,请阅读“我是接收者”
    • 这不仅仅是不同的术语。您可以发送没有相应方法的消息。不能调用不存在的方法。
    • @Adam:您命名了三种消息传递语言,您可以在其中无需相应的方法发送消息,并命名了一种您不能发送的非消息语言。这和我说的有什么不同?
    • 因为它不是“消息传递”与“方法调用”。我可以在 C++ 和 C# 中构造运行时方法调用。我们在这些 cmets 中谈论“后期绑定”与“早期绑定”(或者可能是“动态调度”);我认为真正进入细节对 OP 没有多大帮助。
    【解决方案2】:

    包含此代码的任何对象都在发送消息 - 大概是 main。让我们用更明确的对象和正常的消息传递来看看它。

    class Person
      attr_accessor :first_name, :last_name
      def initialize(first_name, last_name)
        @first_name, @last_name = first_name, last_name
      end
      def marry(other)
        self.last_name = other.last_name
      end
    end
    
    bob = Person.new('Bob', 'Smith')
    patty = Person.new('Patricia', 'Johnson')
    
    patty.marry bob
    

    在这段代码的最后一行,main 向 patty 发送了marry,而 patty 又向自己发送了last_name= 并发送了 bob last_name

    【讨论】:

    • 我们怎么知道“main 正在向 patty 发送结婚”而不是“patty 正在对自己调用结婚”?
    • Patty 正在执行结婚方法——以响应我们的信息。我们可以删除结婚方法并实现method_missing,即使不再调用结婚方法,我们仍然会看到并能够响应消息。
    • 对不起,我理解的很慢。我仍然不明白为什么你的最后一点表明 main 是消息的来源而不是 patty。
    • 发送者是发送消息的人这一事实是语言的一种先验事实。 Smalltalk 被认为是一堆通过消息相互通信的自治对象,而 Ruby 继承了这一理念。如果您想演示这里有两个不同的发件人,请致电private :marry。帕蒂仍然可以告诉自己结婚,但您的消息将被拒绝。或者做 Array.new.
    • "private :marry" 为类 Object 生成“未定义的方法 'marry'”。我不确定这表明了什么。但是“puts Array.new.
    【解决方案3】:

    我知道您在哪里感到困惑,但问题主要是语义上的。你的论点是send 方法应该真的是receive,因为k接收 一条消息(即k.receive :hello)。在简单的英语中,您将k.send :hello 读为“k 发送消息'hello'(给谁?)”,而不是“k 发送消息'hello'”。

    可以将方法重命名为“receive”,但这也有点用词不当,因为k 可能接收到消息——k 可能不响应消息,k 可以选择忽略它,或者k 可以选择将其传递给另一个对象。在 Ruby(以及影响 Ruby 的 Smalltalk)中,方法更像是 requests 来做某事,而不是 commands 来做某事。

    【讨论】:

    • 是的,你已经理解我的语义混淆了。但我不明白你的意思——“k 可能不会收到消息——k 可能不会响应消息,k 可能会选择忽略它,或者 k 可能会选择将它传递给另一个对象” k 忽略该消息?
    • 在 Smalltalk 中,完全相同的方法称为 perform:,我认为这是一个更好的名称。
    • @lorz:几个原因:k可能没有实现方法'hello',或者它可能选择在其实现中什么都不做;或者它可以将消息传递给另一个对象。我对“忽略”的选择可能很差(因为在例如 Java 中,您可能有一个根本不做任何事情的方法实现)。 //@查克:我同意。我认为 Cocoa 框架也使用了 performSelector: 这个名称。
    • @lorz:详细地说,当您在 Ruby 中调用对象的方法时,会向对象发送“消息”(消息是方法的名称)。如果该方法未实现,则调用名为“method_missing”的方法,再次使用原始消息的名称。对象可以选择在 method_missing 中做某事(例如,Rails 在很大程度上使用它),或者它可能丢弃消息,或者它可能什么都不做(因此默认引发异常),或者它可能将消息传递给另一个对象。
    • @mipadi - 谢谢。这清除了链的接收部分。不过,我仍然不清楚的是我们如何识别消息的发送者。在查克的例子中,他说“主要是给帕蒂送婚”。什么是“main”,我们如何知道“main”是消息的来源?
    猜你喜欢
    • 2021-10-08
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多