Ruby 发送时不带符号

发布于 2024-09-07 10:57:02 字数 332 浏览 4 评论 0 原文

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

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

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

但是我不太喜欢这个。还有其他办法吗?

Is it possible to send nothing to an object?

Let me elaborate. For instance I could have something like this:

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

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

The above call wont't work because nil is not a symbol. So the solution is:

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

However I'm not too fond of this. Is there any other way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

勿忘初心 2024-09-14 10:57:03

我不知道有任何方法可以在不带任何参数的情况下返回 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"

I'm not aware of any method that returns self without taking any arguments (but I might be overlooking something), but there's no reason you couldn't monkeypatch one into the class you're using:

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"
在风中等你 2024-09-14 10:57:03

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

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

There is not builtin way. You could do the following:

module Kernel
  def __self__
    self
  end
end

obj1.obj2.send(val || :__self__).obj3.obj4

even more cryptic:

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

but I'd recommend keeping it simple:

intermediate = obj1.obj2
intermediate = intermediate.some_val if some_stack.include?(some_val)
intermediate.obj3.obj4
说谎友 2024-09-14 10:57:03

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

在 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 (并且悄悄地不执行任何操作)用于发送。

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

警告:重新定义“发送”可能会导致严重问题

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

I might be misunderstanding something, but I think this question is attempting to do something that doesn't make sense.

In Ruby, sending a message to an object means asking that object to respond in some way to the requested message (which is specified in this case with a symbol). A message is what we usually refer to as a method call. In this example "send" is a message sent to the object, and the object that receives the message "send" takes the passed arguments (a symbol for another method) and sends itself (the object) a message corresponding to the method for the passed symbol.

So sending an object nil is almost equivalent to not sending the object anything— except that you have actually sent the object a message, only one that doesn't have any content. So the object is inevitably confused as to what it's supposed to do, since it was told to do nothing. Wouldn't you be confused too if someone demanded you do nothing?:)

So to turn to your specific question:

To rephrase your question (to be clear whether I understand it), I think you are asking: is it possible to chain a series of calls wherein one of the calls in the chain only occurs if a variable (the method to call by way of sending a message) is non-nil?

Perhaps this is better for a general purpose solution?

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

Otherwise, to actually answer your question (which now does make sense, but might make things more convoluted), you can put this in your class:

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

Alternatively you can do this:

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

Which will cause every object to accept nil (and quietly do nothing) for send.

This solution will provoke a warning [sic]:

warning: redefining `send' may cause serious problem

You can suppress this warning by redirecting $stderr, but it's not threadsafe (says Matz, from a brief Google search).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文