为什么要定义一个名为 !打破IRB?
Why does defining a method called ! break 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:在 class 之外覆盖 !
是一件 非常 奇怪的事情!有无数种方法可以 "break" ruby 通过做这样疯狂的事情 - 所以你可能会发现玩弄这些奇怪的想法很有趣,但显然不要在重要的代码中这样做!
在ruby中,全部 class继承自top-level基础class:BasicObject
。这 class defines top-level object negation - 即每当你写
!foo
这实际上是在您的对象 foo
:
上调用一个名为 !
的 方法
foo.send(:!)
这使得 重新定义 特定 class 上的方法成为可能(尽管这是一件非常罕见的事情!)。例如,在实现 null object pattern 时,您可以这样做:
class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false
(通常,只有 对象 return false
在上面的行中是 nil
和 false
! )
那么,回到你的例子。您实际上在这里所做的是在 class Object
上定义一个名为 !
的方法(并且没有调用 super
来触发原始方法!)。换句话说,您基本上 re-defined 响应是一种在内部 到处 使用的基本方法。某处某处 (??) 被这种奇怪的行为弄糊涂了,结果失败了 non-gracefully.
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#!>
这里有一些其他方法可以 re-define 导致奇怪 behaviour/errors 的方法,例如:
def nil?
true
end
# Will now die in weird ways!
class String
def ===(other)
true
end
end
"ruby" === "awesome"
#=> true
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:在 class 之外覆盖 !
是一件 非常 奇怪的事情!有无数种方法可以 "break" ruby 通过做这样疯狂的事情 - 所以你可能会发现玩弄这些奇怪的想法很有趣,但显然不要在重要的代码中这样做!
在ruby中,全部 class继承自top-level基础class:BasicObject
。这 class defines top-level object negation - 即每当你写
!foo
这实际上是在您的对象 foo
:
!
的 方法
foo.send(:!)
这使得 重新定义 特定 class 上的方法成为可能(尽管这是一件非常罕见的事情!)。例如,在实现 null object pattern 时,您可以这样做:
class NullObject
def !
true
end
end
my_null = NullObject.new
!!my_null #=> false
(通常,只有 对象 return false
在上面的行中是 nil
和 false
! )
那么,回到你的例子。您实际上在这里所做的是在 class Object
上定义一个名为 !
的方法(并且没有调用 super
来触发原始方法!)。换句话说,您基本上 re-defined 响应是一种在内部 到处 使用的基本方法。某处某处 (??) 被这种奇怪的行为弄糊涂了,结果失败了 non-gracefully.
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#!>
这里有一些其他方法可以 re-define 导致奇怪 behaviour/errors 的方法,例如:
def nil?
true
end
# Will now die in weird ways!
class String
def ===(other)
true
end
end
"ruby" === "awesome"
#=> true