16.2 信息、警告和错误
我们已经在很多场合下见过print
函数,它能把变量显示到控制台。R有三种函数能把程序状态的诊断信息显示出来。根据严重程度由小到大排序,它们分别是message
、warning
和stop
。
message
能把它所有的输入拼接起来,中间不需要任何的空格,然后把它们都写到控制台。它常用于对长时间运行的函数提供状态更新,或当要改变一个函数时把新的行为通知给用户,又或是提供默认参数的信息:
f <- function(x)
{
message("'x' contains ", toString(x))
x
}
f(letters[1:5])
## 'x' contains a, b, c, d, e
## [1] "a" "b" "c" "d" "e"
比起print
(或更低级的cat
),消息(message
)函数的主要优点是用户可以关闭其显示。虽然这看似微不足道,但是当你要重复运行相同的代码时,就可以避免总是不断地看到同样的消息,令你倍受鼓舞:
suppressMessages(f(letters[1:5]))
## [1] "a" "b" "c" "d" "e"
警告(warning)的行为与消息非常相似,但它还有一些额外的特性能特别指出坏消息。警告适用于以下情景:当系统出了问题,但并非错得离谱以致于你的代码放弃执行。常见的例子是:糟糕的用户输入、较差的数值精度,或意想不到的副作用:
g <- function(x)
{
if(any(x < 0))
{
warning("'x' contains negative values: ", toString(x[x < 0]))
}
x
}
g(c(3, -7, 2, -9))
## Warning: 'x' contains negative values: -7, -9
## [1] 3 -7 2 -9
和消息一样,警告可以被抑制:
suppressWarnings(g(c(3, -7, 2, -9)))
## [1] 3 -7 2 -9
有一个全局选项warn
,它确定如何处理警告。默认情况下warn
取值为0
,这意味着只有当你的代码运行完毕,警告才会出现。
使用getOption
可见warn
选项的当前级别:
getOption("warn")
## [1] 1
如果该值小于零,所有的警告都将被忽略:
old_ops <- options(warn = -1)
g(c(3, -7, 2, -9))
## [1] 3 -7 2 -9
但通常来说,完全关闭警告是很危险的,所以你应该使用以下命令把选项重置为之前的状态:
options(old_ops)
把warn
设置为1
意味着只要发生了警告就马上显示它们,如果值为2
或其他更大的值则意味着所有的警告都将变成错误。
可以通过输入last.warning
访问最后发生的警告。
我们在前面曾提到,如果warn
选项设置为0
,那么当你的代码运行完成后才会显示警告。其实这稍微有点复杂。如果只生成了10个或更少的警告,那么之前的说法完全正确。但是如果警告超过10个,你会得到一个消息,说明一共已经生成了多少次警告,而你也必须键入warnings()
来查看它们。如图16-1所示。
图16-1:警告出现次数多于10个时,使用warning
来查看它们
错误(error)是最严重的情况,且会停止程序的执行。错误应该只用于错误发生时,或者你知道错误将会发生时。常见的原因包括无法纠正的(例如,通过as.*
函数)错误输入,无法读取或写入文件,或严重的数值误差:
h <- function(x, na.rm = FALSE)
{
if(!na.rm && any(is.na(x)))
{
stop("'x' has missing values.")
}
x
}
h(c(1, NA))
## Error: 'x' has missing values.
如果任何传递给stopifnot
的表达式被判定为假时,它会抛出一个错误。这里提供了一个简单的方法来检查程序的状态是否符合预期:
h <- function(x, na.rm = FALSE)
{
if(!na.rm)
{
stopifnot(!any(is.na(x)))
}
x
}
h(c(1, NA))
## Error: !any(is.na(x)) is not TRUE
对于更广泛的人性化的测试,使用assertive
包:
library(assertive)
h <- function(x, na.rm = FALSE)
{
if(!na.rm)
{
assert_all_are_not_na(x)
}
x
}
h(c(1, NA))
## Error: x contains NAs.