泛化函数
函数是用于解决一些特定问题的特定逻辑或者过程的集合的一种合理抽象,开发人员
通常希望函数具有一般性,以适用于各种各样的场景。这样就可以轻松地使用它来解决相
似的问题,而无需为每个问题编写过多的专用函数。
泛化是使一个函数具有更广泛的适用性。在弱类型的编程语言(例如 R )中泛化函数
非常方便的,但是当它被不正确地执行时,也会出现错误。
为了使 add( )函数更加通用,以便可以处理各种原始代数运算,我们可以定义另一
个名为 calc 的函数。这个新函数包含 3 个参数:x、y 和 type,其中 x 和 y 是两个向量,
type 接收一个字符向量,它表示用户想要进行哪一种代数运算。
以下代码使用控制流(flow control)执行该函数。我们稍后会讲解控制流的具体使用。虽
然这里初次遇到,但应该很容易理解。在这段代码中,type 的取值决定了使用何种表达式。
calc <- function(x, y, type){
if (type == "add"){
x + y
} else if (type == "minus"){
x - y
} else if (type == "multiply"){
x * y
} else if (type == "divide"){
x / y
}else {
stop("Unknown type of operation")
}
}
一旦函数被定义,我们便可以通过提供适当的参数来调用它:
calc(2, 3, "minus")
## [1] –1
函数自动适用于数值向量:
calc(c(2, 5), c(3, 6), "divide")
## [1] 0.6666667 0.8333333
因为之前“+”已经被良好定义,所以也可以泛化 calc( )函数以适用于非数值向量:
calc(as.Date("2014-06-01"), 3, "add")
## [1] "2014-06-04"
如果提供一些无效参数:
calc(1, 2, "what")
## Error in calc(1, 2, "what"): Unknown type of operation
在这种情况下,没有满足的条件,因此最后 else 代码块中的表达式被执行。stop( )
函数被调用,输出错误信息并立即终止运算。
看起来函数运行良好,也考虑了包括无效参数的所有情况。然而事实并非如此:
calc(1, 2, c("add", "minus"))
## Warning in if (type == "add") {: 条件的长度大于一,因此只能用其第一元素
## [1] 3
这里,我们没有考虑传递多元素向量给 type 的情况。问题在于:当两个多元素向量
比较时,也会返回一个多元素逻辑向量,这会使得 if 的判断条件含糊不清。考虑一下,
if(c(TRUE, FALSE))意味着什么呢?
为了彻底地避免这种模棱两可的情况,我们需要细化函数使错误能够更加明晰,反映
更多信息。进一步地,我们只需检查向量的长度是否为 1:
calc <- function(x, y, type){
if (length(type > 1L)) stop("Only a single type is accepted")
if (type == "add"){
x + y
} else if (type == "minus"){
x - y
} else if (type == "multiply"){
x * y
} else if (type == "divide"){
x / y
}else {
stop("Unknown type of operation")
}
}
重试上述会报错的代码,我们可以查看预先检查参数后,函数如何处理异常:
calc(1, 2, c("add", "minue"))
## Error in calc(1, 2, c("add", "minue")): Only a single type is accepted