为什么定义一个名为 ! 的方法会破坏 IRB?



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。

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

在 ruby 中,所有类都继承自顶级基类:BasicObject。此类定义了顶级对象否定 - 即每当你写

!foo

这实际上是在对象上调用一个名为!的方法foo

foo.send(:!)

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

class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false

(通常,在上面行中返回false的唯一对象是nilfalse

现在,回到你的例子。您在这里实际做的是在类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

相关内容

  • 没有找到相关文章

最新更新