1

IRB 在定义一个名为!.

要重现这一点,请在 IRB 中输入以下内容:

def !
  puts "foo"
end

创建方法后,IRB 会无限打印foo

irb(main):001:0> def !
irb(main):002:1>   puts "foo"
irb(main):003:1> end
foo
foo
foo
...

据我所知,您不能直接调用以!Ruby 语法命名的方法;你必须send改用。 编辑:您可以作为前缀运算符调用;!这只是否定:!x

为什么这个定义会导致 IRB 无限循环?IRB 是否依赖于一种名为!打印其提示或类似内容的方法?

我在 Windows 10 上使用 Ruby 2.4.3 和 IRB 0.9.6。

4

1 回答 1

2

tl; dr:!在类之外覆盖是一件非常奇怪的事情!有无数种方法可以通过做这样疯狂的事情来“破坏”ruby - 所以你可能会发现玩这些奇怪的想法很有趣,但显然不要在重要的代码中这样做!

在 ruby​​ 中,所有类都继承自顶级基类:BasicObject. 此类定义顶级对象否定- 即每当您编写

!foo

这实际上是在调用您的对象上调用的方法!foo

foo.send(:!)

这使得重新定义特定类的方法成为可能(尽管这是一件非常罕见的事情!) 。例如,在实现空对象模式时,您可以执行以下操作:

class NullObject
  def !
    true
  end
end

my_null = NullObject.new
!!my_null #=> false

(通常,在上面一行中返回的唯一对象是和!)falsenilfalse

现在,回到你的例子。你在这里实际上做的是定义一个!在类上调用的方法Object(并且没有调用super来触发原始方法!)。换句话说,您基本上将响应重新定义为一种在内部到处使用的基本方法。某事,某处(??)被这种奇怪的行为弄糊涂了,并且不优雅地失败了。

irb(main):001:0> def !
irb(main):002:1> puts "foo"
irb(main):003:1> super # <-- !! This stops it from breaking completely !!
irb(main):004:1> end
=> :!
irb(main):005:0* method(:!)
foo
foo
=> #<Method: Object#!>
irb(main):006:0> method(:!).source_location
foo
foo
=> ["(irb)", 1]
irb(main):007:0> method(:!).super_method
foo
foo
=> #<Method: BasicObject#!>

以下是您可以重新定义导致奇怪行为/错误的方法的其他一些方法,例如:

def nil?
  true
end
# Will now die in weird ways!

class String
  def ===(other)
    true
  end
end

"ruby" === "awesome"
#=> true
于 2018-03-28T19:52:41.043 回答