2013-10-31 98 views
2

編輯:不要打擾讀這個問題,我只是不能刪除它。它基於破碎的代碼,這裏幾乎沒有什麼可學的。

我重定向控制檯輸出在我的Ruby程序,雖然它完美的作品有一兩件事我很好奇:

這裏是我的代碼

capture = StringIO.new 
$stdout = capture 
puts "Hello World" 

看起來即使我m將capture對象分配給$stdout,$stdout在賦值後包含一個新的不同對象,但至少該類型是正確的。

換句話說:

$stdout.to_s    # => #<IO:0x2584b30> 

capture = StringIO.new 
$stdout = capture 

$stdout.to_s    # => #<StringIO:0x4fda948> 
capture.to_s    # => #<StringIO:0x4e3b220> 

隨後$stdout.string包含"Hello World",但capture.string是空的。

在幕後發生了什麼或者我在這裏錯過了什麼嗎?

編輯:這可能只針對某些版本。我在Windows 8.1上使用Ruby 2.0.0-p247

+0

也許它是重複? –

+0

是你的實際代碼嗎? – Stefan

+0

對不起,Felix和falsetru是正確的,'$ stdout'的值隨後發生了變化。我沒有注意到,因爲'Hello World'這行代碼實際上是一個代碼的佔位符,我從別人那裏繼承過來,而且我沒有非常徹底地檢查它。 - 那太浪費時間了,但是謝謝你幫助我! –

回答

1

你確定沒有其他操作$stdoutcapture之間發生?

對我來說,輸出看起來不一樣。無論capture$stdout是同一個對象,並隨後回答string具有相同的響應(紅寶石1.9.2):

require 'stringio'                                
$stdout.to_s    # => #<IO:0x2584b30>                         

capture = StringIO.new                               
$stdout = capture                                

puts $stdout.to_s    # => #<StringIO:0x89a38c0>                      
puts capture.to_s    # => #<StringIO:0x89a38c0>                      
puts "redirected" 

$stderr.puts $stdout.string # => '#<StringIO:0x89a38c0>\n#<StringIO:0x89a38c0>\nredirected'                   
$stderr.puts capture.string # => '#<StringIO:0x89a38c0>\n#<StringIO:0x89a38c0>\nredirected' 
+0

我擔心你可能是對的...現在檢查。 –

2

它按預期工作。

>> capture = StringIO.new 
=> #<StringIO:0x00000001ea8c00> 
>> $stdout = capture 
>> $stdout.to_s 
>> capture.to_s 

上面兩行不打印任何內容,因爲$stdout現在已與終端斷開連接。

所以我用$stderr.puts在以下行(也可以使用STDOUT.puts作爲斯特凡評論):

>> $stderr.puts $stdout.to_s 
#<StringIO:0x00000001ea8c00> 
>> $stderr.puts capture.to_s 
#<StringIO:0x00000001ea8c00> 

$stdout.to_scapture.to_s給我同樣的結果。

我用紅寶石1.9.3。 (相同2.0.0)

+3

您可以使用'STDOUT.puts'來代替。 – Stefan

+0

@斯特凡,啊,你說得對。 – falsetru

+0

當然,我通過其他方式得到了'to_s'值:)正如我所說的,這裏沒有問題,我只是對發生的事情感到好奇。 –

1

雖然這個問題是俯瞰變化的$stdout值的結果,紅寶石確實有以這種方式覆蓋分配給全局變量的能力,至少在C api中,使用hooked variables

$stdout actually does make use of this檢查新值是否是合適的(它檢查whether the new value responds to write),如果它不拋出一個異常。

如果你真的想(你不這樣做),你可以創建它由被稱爲dup定義了一個全局變量,自動存儲不同的對象不是分配價值,也許是推廣和使用,而不是:

#include "ruby.h" 

VALUE foo; 

static void foo_setter(VALUE val, ID id, VALUE *var){ 
    VALUE dup_val = rb_funcall(val, rb_intern("dup"), 0); 
    *var = dup_val; 
} 

void Init_hooked() { 
    rb_define_hooked_variable("$foo", &foo, 0, foo_setter); 
} 

然後,您可以使用它像:

2.0.0-p247 :001 > require './ext/hooked' 
=> true 
2.0.0-p247 :002 > s = Object.new 
=> #<Object:0x00000100b20560> 
2.0.0-p247 :003 > $foo = s 
=> #<Object:0x00000100b20560> 
2.0.0-p247 :004 > s.to_s 
=> "#<Object:0x00000100b20560>" 
2.0.0-p247 :005 > $foo.to_s 
=> "#<Object:0x00000100b3bea0>" 
2.0.0-p247 :006 > s == $foo 
=> false 

當然,這是非常相似,簡單地創建一個類的setter方法是dup S中的淡水河谷並存儲,您可以在純Ruby的事:

def foo=(new_foo) 
    @foo = new_foo.dup 
end 

由於使用全局變量通常是糟糕的設計,所以對於全局變量來說這在Ruby中是不可能的。

相關問題