我遇到了一些看似不寻常的事情,我想知道是否有人能解释原因。
1.8.7 :001 > some_str = "Hello World"
=> "Hello World"
1.8.7 :002 > some_str.try(:match, /^(\w*)/)
=> #<MatchData "Hello" 1:"Hello">
1.8.7 :003 > $1
=> nil
1.8.7 :004 > some_str.match(/^(\w*)/)
=> #<MatchData "Hello" 1:"Hello">
1.8.7 :005 > $1
=> "Hello"
我不确定为什么第一次没有设置全局变量$1
,而是设置第二次。任何见解?
答案 0 :(得分:3)
try
定义为
def try(method, *args, &block)
send(method, *args, &block)
end
当然除了nil之外它只返回nil。为什么这很重要?因为正则表达式全局变量不是真正的全局变量:它们是基于per方法和每个线程维护的(通过仔细阅读ruby源很容易看到它)。当您通过match
致电try
时,全局变量将设置在try
的范围内,但在下一种情况下,它们将设置在顶层。这很容易验证
def do_match string, regexp
string =~ regexp
$1
end
do_match "Hello World", /^(\w*)/ #=> returns 'Hello'
$1 #=> returns nil
答案 1 :(得分:3)
让我告诉你try
是如何实现的。如果您想自己查看,请查看activesupport源。它在/lib/active_support/core_ext/object/try.rb
class Object
def try(*a, &b)
if a.empty? && block_given?
yield self
else
public_send(*a, &b)
end
end
end
这基本上做的是将方法名称和完整参数发送到Object
。 public_send
与send相同,但只能用于调用公共方法。
所以我重写了这个,调试你的问题:
class Object
def try(*a)
result = public_send(*a)
puts $1.inspect
result
end
end
string = "Hello"
string.try(:match, /^(\w*)/)
puts $1.inspect
此输出
"Hello"
nil
所以出现了一个很好的问题:这是ruby解释器中的错误吗?。 也许吧。至少在任何官方来源都没有记录。我找到了一个引用,告诉以下内容(See Global variables。)
[...],
$_
和$~
具有本地范围。他们的名字表明它们应该是全球性的,但它们在这方面更有用,并且使用这些名称有历史原因。
所以似乎$1
也不是全局变量,即使它被内核报告为全局变量:
1.9.3-p194 :001 > global_variables
=> [:$;, :$-F, :$@, :$!, :$SAFE, :$~, :$&, :$`, :$', :$+, :$=, :$KCODE, :$-K,
:$,, :$/, :$-0, :$\, :$_, :$stdin, :$stdout, :$stderr, :$>, :$<, :$.,
:$FILENAME, :$-i, :$*, :$?, :$$, :$:, :$-I, :$LOAD_PATH, :$",
:$LOADED_FEATURES, :$VERBOSE, :$-v, :$-w, :$-W, :$DEBUG, :$-d, :$0,
:$PROGRAM_NAME, :$-p, :$-l, :$-a, :$binding, :$1, :$2, :$3, :$4, :$5, :$6,
:$7, :$8, :$9]
为了确保这一点,我将此错误转发给Ruby Bug Tracker。见Ruby Bug #6723