【问题标题】:Ruby send with no symbolRuby 发送无符号
【发布时间】:2011-03-07 10:20:52
【问题描述】:

是否可以不向对象发送任何内容?

让我详细说明。例如我可以有这样的东西:

val = some_stack.include?(some_val) ? some_val : nil

obj1.obj2.send(val).obj3.obj4

上面的调用不起作用,因为 nil 不是符号。所以解决办法是:

if val.nil?
  obj1.obj2.obj3.obj4
else
  obj1.obj2.send(val).obj3.obj4
end

不过我不太喜欢这个。有没有其他办法?

【问题讨论】:

    标签: ruby send


    【解决方案1】:

    我可能会误解某些东西,但我认为这个问题试图做一些没有意义的事情。

    在 Ruby 中,向对象发送消息意味着要求该对象以某种方式响应请求的消息(在本例中使用符号指定)。消息就是我们通常所说的方法调用。在本例中,“send”是发送给对象的消息,接收“send”消息的对象接受传递的参数(另一个方法的符号)并向自身(对象)发送与该方法对应的消息通过符号。

    因此,发送一个 nil 对象几乎等同于不向该对象发送任何内容——除了您已经实际上向该对象发送了一条消息,只是一条没有任何内容的消息。所以对象不可避免地会混淆它应该做什么,因为它被告知什么也不做。如果有人要求你什么都不做,你不会也感到困惑吗?:)

    所以转向你的具体问题:

    重新表述您的问题(要清楚我是否理解),我想您是在问:是否可以链接一系列调用,其中链中的一个调用仅在变量(调用方法通过发送消息)是非零的?

    也许这对于通用解决方案更好?

    obj2 = obj1.obj2
    obj2 = obj2.send( val ) if val
    obj2.obj3.obj4
    

    否则,要真正回答您的问题(现在确实有道理,但可能会使事情变得更加复杂),您可以将其放入您的课程中:

    def send( method, *args )
        super if method
    end
    

    您也可以这样做:

    class Object
        def send( method, *args )
            super if method
        end
    end
    

    这将导致每个对象接受 nil(并且悄悄地什么都不做)发送。

    此解决方案将引发警告 [原文如此]:

    警告:重新定义 `send' 可能会导致严重问题

    您可以通过重定向 $stderr 来抑制此警告,但它不是线程安全的(Matz 说,来自简短的 Google 搜索)。

    【讨论】:

      【解决方案2】:

      没有内置方式。您可以执行以下操作:

      module Kernel
        def __self__
          self
        end
      end
      
      obj1.obj2.send(val || :__self__).obj3.obj4
      

      更加神秘:

      [:obj1, :obj2, val, :obj3, :obj4].compact.inject(self, :send)
      # (assuming that obj1 is a method call like obj2, ...)
      

      但我建议保持简单:

      intermediate = obj1.obj2
      intermediate = intermediate.some_val if some_stack.include?(some_val)
      intermediate.obj3.obj4
      

      【讨论】:

        【解决方案3】:

        我不知道有任何方法在不带任何参数的情况下返回 self(但我可能忽略了一些东西),但你没有理由不能将一个猴子补丁添加到你正在使用的类中:

        irb(main)> class Object
        irb(main)>   def ignore
        irb(main)>     self
        irb(main)>   end
        irb(main)> end
        => nil
        irb(main)> msg = nil
        => nil
        irb(main)> 'hi'.send(msg || :ignore).upcase
        => "HI"
        irb(main)> msg = :reverse
        => :reverse
        irb(main)> 'hi'.send(msg || :ignore).upcase
        => "IH"
        

        【讨论】:

        • 从 Ruby 2.2 开始,可以使用Kernel#itself,不再需要打补丁了。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-02
        • 1970-01-01
        • 1970-01-01
        • 2017-10-08
        • 2020-09-10
        • 2019-07-03
        • 1970-01-01
        相关资源
        最近更新 更多