R:为什么在省略号是最后一个参数时为省略号 (...) 提供一个列表不起作用?

R: why providing a list to ellipsis (...) when ellipsis is the last argument does not work?

我正在编写一个利用省略号(又名 ...)的函数。它允许您指定数量可变的附加参数。我想提供一个带有参数的列表作为附加参数。下面是一个可重现的例子:

f <- function(..., a =1, b = 2){
  l <- list(...)
  print(l)
}
f(list(a = 2))

[[1]]
[[1]]$a
[1] 2

在列表中提供额外参数的目的是避免名称冲突(f 中的函数可以采用名为 a 的参数,我想确保提供它的可能性)。

在更改实现时,我注意到将省略号移动到函数声明的最后位置 returns 不同的结果(即空列表):

g <- function(a =1, b = 2, ...){
  l <- list(...)
  print(l)
}
g(list(a = 2))

list()

出于好奇,我向两个函数添加了打印默认参数:

f <- function(..., a =1, b = 2){
  l <- list(...)
  print(l)
  print(c(a = a, b = b))
}
g <- function(a =1, b = 2, ...){
  l <- list(...)
  print(l)
  print(c(a = a, b = b))
}

f(list(a = 2)) # results of calling f
[[1]]
[[1]]$a
[1] 2


a b 
1 2

g(list(a = 2)) # results of calling g
list()
$a.a
[1] 2

$b
[1] 2

因此,第一个函数 (f) 返回了预期的输出,但第二个函数 (g) 忽略了(?) 默认参数 a 并以某种方式修改了提供的列表感谢省略号。

我想了解为什么两个输出彼此不同。这是否意味着只有当省略号是函数调用中的第一个参数时,才可以将列表作为附加参数传递?

我认为如果您在函数调用中不使用 list,该函数将按预期工作:f(a=2)g(a=2) 都会 return list()变量的值 l.

由于您将列表作为参数传递,它被视为未命名变量并分配给第一个形式参数,fg 不同。

如果您愿意 do.call(f, list(a=2))do.call(g, list(a=2)),情况又会有所不同。在这种情况下,值 2 将分配给预期的形式参数 a.

参数在 R 中的工作方式是,当您不命名第一个参数时,R 只是假设它进入函数的第一个参数。对于参数列表中的第二个、第三个等等参数都是如此,除了 ... 之后的参数 - 因为 R 不知道您打算将多少个参数放入 ...,如果你想改变它后面的默认值,你必须给它命名。

所以在你的例子中,当你调用函数 f() 时,对象 list(a=2) 进入 ...。但是在 g() 中,同一个对象进入 a。当它被放置在参数列表的末尾而不包括 a 和 b 的参数时,你可以将它放入 ... 的唯一方法是将它命名为不是 a 或 b 的东西,例如g(c=列表(a=1)).

您问题的简短回答这是否意味着仅当省略号是函数调用中的第一个参数时才可以将列表作为附加参数传递? 是否,如果在函数调用期间传递值时遵循正确的命名或位置,则不会出现参数匹配不正确的问题。

更好的做法是在函数调用中命名参数(至少从第二个参数开始),这样正确的名称匹配就会产生预期的效果。

在函数调用期间未提及名称将执行参数的位置匹配。如果您未能在正确的位置发送正确的值,这可能会导致意想不到的效果。

注意打印输出中参数名称的顺序。它遵循函数中定义的参数顺序。只有正确命名参数,才会出现这种正确的顺序。

当参数命名正确时,无需担心参数的位置。你可以传递任何东西给它。它不一定必须是 list.

f <- function(..., a =1, b = 2){
  mc <- match.call(expand.dots = TRUE )
  print(names(mc))
}
g <- function(a =1, b = 2, ...){
  mc <- match.call(expand.dots = TRUE )
  print(names(mc))
}

f(c1 = list(z = 2, f = 5), a = 1, b = 2)  # [1] ""   "c1" "a"  "b" 
f(a = 1, c1 = list(z = 2, f = 5), b = 2)  # [1] ""   "c1" "a"  "b"
f(a = 1, c1 = list(z = 2, f = 5), b = 2, c2 = 4) # ""   "c1" "c2" "a"  "b" 
f(c1 = list(z = 2, f = 5), 1, 2, 4) # [1] ""   "c1" ""   ""   ""  


g(c1 = list(z = 2, f = 5), a = 1, b = 2)  # [1] ""   "a"  "b"  "c1"
g(a = 1, c1 = list(z = 2, f = 5), b = 2)  # [1] ""   "a"  "b"  "c1"
g(a = 1, c1 = list(z = 2, f = 5), b = 2, c2 = 4) # [1] ""   "a"  "b"  "c1" "c2"
g(c1 = list(z = 2, f = 5), 1, 2, 4) # [1] ""   "a"  "b"  "c1" ""