<- function(a, x, b=0) {
f return(a*x^2 + b)
}
参考 R Language Definition
R 语言中函数中的参数匹配分为 3 步:
参数名称精确匹配
参数名称部分匹配
参数位置匹配
接下来,设计一个简单的函数。这个函数可以计算二次函数的值,即:\(f(x)=ax^2+b\)。其中参数 b
默认为 0
参数名称精确匹配
关键字精确匹配是指在向函数传递实际参数时,实际参数的名称与函数的形式参数的名称一一对应,就算顺序不同,也可以成功传递参数。
f(a=1, x=2)
## [1] 4
f(a=1, x=2, b=3)
## [1] 7
f(x=2, a=1, b=3)
## [1] 7
参数名称部分匹配
每个剩余的实际参数都会使用部分匹配与剩余的形式参数进行比较。如果所提供的实际参数的名称恰好与形式参数匹配,则认为这两个参数匹配成功。否则,不能按照参数名称成功传递参数,比如下面代码中的的 c=3
。
f(1, 2, c=3)
## Error in f(1, 2, c = 3): unused argument (c = 3)
参数位置匹配
所有未匹配的形式参数都会与实际参数按照顺序一一对应。
f(a=1, x=2, 3)
## [1] 7
上面这个例子中,函数先按照名称部分匹配了 a=1
,x=2
,接着再按照位置匹配将实际参数 3 与形式参数 b
对应起来。
f(1, 2, 3)
## [1] 7
上面这个例子中,因为实际参数没有名称,所以函数无法按照名称对参数进行匹配,于是使用位置匹配。其中实际参数 1 对应形式参数 a
,实际参数 2 对应形式参数 x
,实际参数 3 对应形式参数 b
。
特殊的参数 {...}
例 1
参考: R for Data Science
R 中不少函数可以接受任意数量的输入,其原因在于使用了特殊参数 ...
。这个参数会捕获任意数量的未匹配的参数。
sum(1, 2, 3, 4, 5)
## [1] 15
paste("a", "b", "c", sep = " ")
## [1] "a b c"
::str_c("a", "b", "c")
stringr## [1] "abc"
以上的函数还有个共同的特点:不能事先确定传入参数的个数。使用 args
对函数的参数进行查看,发现它们确实都使用了特殊参数 ...
:
args(mean)
## function (x, ...)
## NULL
args(paste)
## function (..., sep = " ", collapse = NULL, recycle0 = FALSE)
## NULL
args(stringr::str_c)
## function (..., sep = "", collapse = NULL)
## NULL
进一步,可以将 ...
捕获的参数的值传递给另一个函数,如:
<- function(...) {stringr::str_c(..., collapse = ", ")}
commas commas(letters[1:10])
## [1] "a, b, c, d, e, f, g, h, i, j"
例 2
之前定义的函数 f
其实是一个向量化的函数,其中的参数 x
不仅可以是标量,还可以是向量。
严格地来说,R 中并没有“标量”这个概念。在 R 看来:“标量”不过是只包含一个元素的向量。
比如:
<- seq(from=-10, to=10, by=0.01) # 生成一个从-10到10,步长为0.01的向量
x = f(1, x, 3) y
然后在坐标轴上画出函数图像:
plot(x, y)
但现在,若想使用一个函数将求值函数 f
与绘图函数 plot
整合起来,应该怎么做?只需要建立一个新函数,将函数 f
与 plot
中的参数放入其中即可:
<- function(a, x, b) {
computeAndplot = f(a, x, b)
y plot(x, y)
}
computeAndplot(1, x, 3)
如果我们想要进一步修改颜色、线条粗细等绘图参数,那就必须将 plot
函数中的相关参数纳入新函数 computeAndplot
中。 问题在于 plot
是一个含有众多参数的一个强大的函数,并且有时我们需要 plot
中的一部分参数,有时我们又需要 plot
中的另一部分参数。若将 plot
的所有参数手动输入到函数 computeAndplot
中,则会为定义函数和使用函数带来大量不便。
为此,使用 ...
来捕获任意数量未匹配的参数,相当于将 ...
中的形式参数打包为一个 list,在使用时传递给内部的函数 plot
。
<- function(a, x, b, ...) {
computeAndplot = f(a, x, b)
y plot(x, y, ...)
}
computeAndplot(1, x, 3, lty=1, col="blue")
这个例子中,a=1, x=x, b=3
在函数 computeAndplot
中按照上文所介绍的3个步骤进行参数匹配,而参数 lty=1, col="blue"
对应函数 computeAndplot
中的 ...
并被打包传递给内部函数 plot
。
computeAndplot(1, x, 3, col="blue", cex=0.5, main="f(x)=x^2+3")
小结
{...}
的作用:可以捕获任意数量未匹配的参数,并传递给其他函数使用场合:不能确定传入参数的个数时;用于扩写已有函数(使用一个函数去包装另一个函数)
优点:参数传递简单、方便
缺点:拼写错误的参数会被
...
捕获,导致不会 raise error,难以发现输入错误