在Ruby中,STDIN和$stdin有什么区别?

42

Ruby有两种方式来引用标准输入:STDIN常量和$stdin全局变量。

除了我可以将不同的IO对象分配给$stdin因为它不是一个常数(例如在子进程中重定向IO之前),STDIN$stdin之间有什么区别?在我的代码中何时应该使用每个变量?

如果我重新分配$stdin,它会影响STDIN吗?

这是否也适用于STDOUT/$stdoutSTDER/$stderr

2个回答

45
如果重新分配$stdin,则不会影响STDIN。同样,如果重新分配STDIN(虽然这是完全可能的(尽管无意义),但会产生警告),$stdin也不会受到影响。但是,如果两个变量都没有被重新分配,则它们都指向同一个IO对象,因此在其中一个上调用reopen¹会影响另一个。
所有内置的Ruby方法都使用$<(又名ARGF)来读取输入。如果ARGV为空,则ARGF$stdin读取,因此如果您重新分配$stdin,将影响所有内置方法。如果您重新分配STDIN,除非某些第三方方法使用STDIN,否则不会产生影响。
在自己的代码中,您应该使用$stdin以与内置方法²保持一致。
¹ reopen是一种可以将IO对象重定向到另一个流或文件的方法。但是,您不能使用它将IO重定向到StringIO,因此它并未消除重新分配$stdin的所有用例。
² 当然,您也可以使用$</ARGF以使代码与内置方法更加一致,但大多数情况下,如果您正在显式使用标准输入流,则不希望使用ARGF行为。

我非常确定内置方法使用$<(默认输入流)和$>(默认输出流),而不是$stdin/STDIN$stdout/STDOUT。事实上,这正是$<$>的主要目的:您可以重定向诸如Kernel#puts之类的方法的输入和输出,而不会影响stdin/stdout。 - Jörg W Mittag
4
@Jörg: 你说得没错,他们使用$<$>,我会进行更正。但是你关于第二点是错误的: $>$stdout是别名,所以重新分配其中一个将影响另一个(与不受影响的STDOUT不同)。$<ARGF相同,两者不能被重新赋值。然而,重新分配$stdin 影响$<ARGF,因为如果ARGV为空,ARGF$stdin读取。 - sepp2k

1

STDERR和$stderr最初指向同一物体;您可以重新分配全局变量,但不应该干扰常量。$stdin和STDIN、$stdout和STDOUT成对出现。

我曾经多次更改STDERR,作为一种替代方法来猴子补丁一些使用STDERR.puts输出错误消息的宝石。如果您使用STDERR = $stdout重新分配,则会收到警告,而STDERR.reopen('nul','w')则不言自明。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接