TL;DR
当为S3对象制作print.*()
函数时,应使用cat()
。对于其他所有情况,请使用message()
,除非程序的状态有问题。例如,可恢复的错误使用warning()
,而致命错误使用stop()
。
目标
本文的目的是提供反馈,介绍包开发人员可以访问的不同输出选项以及如何构造基于新对象或基于字符串的输出。
R输出概述
传统的输出函数有:
print()
(打印)
cat()
(连接)
message()
(信息)
warning()
(警告)
stop()
(停止)
现在,前两个函数(
print()
和
cat()
)将它们的输出发送到
stdout
或标准输出。而最后三个函数(
message()
,
warning()
和
stop()
)将它们的输出发送到
stderr
或标准错误。也就是说,像
lm()
这样的命令的
结果输出被发送到一个文件,而错误输出(如果存在)则被发送到完全不同的文件。这对用户体验特别重要,因为诊断信息不会混杂在日志文件中的结果输出中,而错误信息可以快速搜索。
为用户和外部包设计
现在,上述内容更多地以I/O思维为基础,而不是面向用户的框架。因此,让我们在日常R用户的背景下提供一些动机。特别是,通过使用3-5个或
stderr
函数,它们的输出可以被抑制,而不需要通过
sink()
或
capture.output()
来调整控制台文本。抑制通常以
suppressWarnings()
,
suppressMessages()
,
suppressPackageStartupMessages()
等形式出现。因此,用户只会面对结果导向的输出。如果您计划允许用户在创建动态文档时关闭基于文本的输出,这一点尤其重要,可以使用
knitr,
rmarkdown, 或
Sweave。
特别是,
knitr
提供了一些代码块选项,如
error = F
、
message = F
和
warning = F
。这使得文档中伴随命令的文本减少了。此外,这也避免了使用
results = "hide"
选项来禁用所有输出的需要。
输出细节
print()
首先,我们有一个老牌但好用的函数print()
。该函数有一些严重的限制。其中之一是缺乏嵌入式术语连接。第二个,可能更严重的是,每个输出都以[x]
开头,后面跟着实际内容周围的引号。这里的x
指的是正在打印的元素编号。这对于调试很有帮助,但在此之外没有任何作用。
例如:
print("Hello!")
[1] "Hello!"
对于字符串拼接,我们依赖于paste()
函数与print()
同步工作:
print(paste("Hello","World!"))
[1] "Hello World!"
另外,可以使用paste0(...)
函数代替paste(...)
函数,以避免paste()
函数的sep = " "
参数默认使用空格在元素之间进行连接。即不带空格的连接。
例如:
print(paste0("Hello","World!"))
[1] "HelloWorld!"
print(paste("Hello","World!", sep = ""))
[1] "HelloWorld!"
cat()
另一方面,cat()
解决了所有这些批评。最值得注意的是,cat()
函数内置了 paste()
功能的 sep=" "
参数,使您可以跳过编写 paste()
而直接使用它。然而,cat()
函数的唯一缺点是您必须通过在结尾添加 \n
或使用 fill = TRUE
(使用默认打印宽度)来强制换行。
例如:
cat("Hello!\n")
Hello!
cat("Hello","World!\n")
Hello World!
cat("Hello","World!\n", sep = "")
HelloWorld!
正是因为这个原因,设计print.*()
S3方法时应该使用cat()
。
message()
message()
函数比cat()
更好!原因是输出与传统纯文本不同,它被定向到 stderr
而不是 stdout
。例如:他们将颜色从标准黑色输出更改为红色输出,以吸引用户的注意。
此外,您还可以使用内置的
paste0()
功能。
message("Hello ","World!") # Note the space after Hello
"Hello World!"
此外,
message()
还提供了一个错误状态,可与
tryCatch()
一起使用。
例如:
tryCatch(message("hello\n"), message=function(e){cat("goodbye\n")})
goodbye
warning()
warning()
函数不是随意使用的东西。warning函数与message函数的区别主要在于它有一行前缀("Warning message:"
)并且其状态被认为是有问题的。
Misc: 在函数中随意使用可能会在尝试将软件包上传到
CRAN时不经意地触发心碎,因为示例检查和警告通常被视为“错误”。
stop()
最后,我们有stop()
。它通过完全杀死正在进行的任务并将控制权交还给用户将警告提升到了更高的级别。此外,它具有最严重的前缀,术语"Error:"
被添加。
message()
也会发出“消息”,这就是suppressMessages()
捕获的内容。suppressMessages()
不会抑制纯stderr输出,例如suppressMessages(cat("hello\n", file=stderr()))
仍然会在控制台中显示hello
。 - HenrikBstop
、warning
、message
都是信号条件,这也是它们可以被捕获/抑制的原因。例如:tryCatch(message("hello"), message=force)
;如果意图是发出诊断条件信号,则使用cat(file=stderr())
是不好的风格(而且无效,正如你的示例所说明的那样!)。 - Martin Morgan