17.8 包的维护
函数对用户来说就像是一个黑盒子。他们会给它传递一些参数然后函数也会返回一些值,用户不需要关心函数内部发生了什么(至少理论上如此)。这意味着,一个函数的签名(即函数的名称及参数的顺序)不应该没有警告用户就直接更改。R提供了一些函数能帮助通知用户签名已改变。
如果你正计划增加一个新的功能但还没有机会实现它,或想提前通知你的用户此功能将至,可以使用.NotYetUsed
函数。如果用户试图过早地使用它,这将抛出一个错误或警告,理由是它还不能使用。在下例中,我们将为hypotenuse函数添加一个二维的p范数。在添加新的功能之前,我们只需更改其签名,并且在用户尝试使用p
参数时抛出一个错误:
hypotenuse <- function(x, y, p = 2)
{
if(!missing(p))
{
.NotYetUsed("p")
}
sqrt(x ^ 2 + y ^ 2)
}
hypotenuse(5, 12) # 行为与之前的一样
## [1] 13
hypotenuse(5, 12, 1)
## Error: argument 'p' is not used (yet)
一旦我们添加了新的功能,可以删除.NotYetUsed
:
hypotenuse <- function(x, y, p = 2)
{
(x ^ p + y ^ p) ^ (1 / p)
}
如果你想添加一个全新的功能(而不仅仅是一个参数),对应的函数是.NotYetImplemented
。当你第一次创建包或添加一大块功能时这非常适用。编写单个函数会非常耗时,所以当写完一些代码,你可能已忘记其他本来要添加的函数。因此,有时最好是先完成上层的设计,然后再逐步实现具体的底层细节。只需简单地为每个函数先创建一个占位符,在函数体中先使用.NotYetImplemented
代替。下例中的函数将会在以后某一天才开始计算三角数,不过它现在只会抛出一个错误:
triangular <- function(n)
{
.NotYetImplemented()
}
triangular()
## Error: 'triangular' is not implemented yet
如果你想删除一个函数,最礼貌的做法是是分阶段完成。第一步是在函数内添加一个.Deprecated
的调用,其参数为它所要替代的函数的名称。该函数的其余部分应保持不变,从而能够保留现有的行为:
hypotenuse <- function(x, y, p = 2)
{
.Deprecated("p_norm")
(x ^ p + y ^ p) ^ (1 / p)
}
hypotenuse(5, 12)
## Warning: 'hypotenuse' is deprecated. Use 'p_norm' instead. See
## help("Deprecated")
## [1] 13
经过一段适当长的时间——足以让你的用户注意到相关函数过时的消息,你就可以改变函数的内容,让它调用.Defunct
,这将抛出一个错误:
hypotenuse <- function(x, y, p = 2)
{
.Defunct("p_norm")
}
hypotenuse(5, 12)
## Error: 'hypotenuse' is defunct. Use 'p_norm' instead. See help("Defunct")