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()。这个函数有一些严重的限制。其中之一是缺乏嵌入的术语连接。第二个,可能更严重的是,每个输出前面都有[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() 解决了所有这些批评。最值得注意的是,paste() 功能的sep=" " 参数是内置的,允许在cat() 中跳过写入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() 功能甚至比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 message:"),并且它的状态被认为是有问题的。
其他:由于示例检查和警告通常被视为“错误”,因此在尝试将包上传到 CRAN 时,在函数中随意使用可能会无意中触发心碎。
停止()
最后但同样重要的是,我们有stop()。通过完全终止手头的任务并将控制权返回给用户,这将警告提升到了一个新的水平。此外,它有最严重的前缀,添加了术语"Error:"。