使用 match.call 将所有参数传递给其他函数

Posted

技术标签:

【中文标题】使用 match.call 将所有参数传递给其他函数【英文标题】:Use match.call to pass all arguments to other function 【发布时间】:2015-06-02 08:37:45 【问题描述】:

来自?match.call

match.call 最常用于两种情况: […] 将大部分调用传递给另一个函数 […]

读完之后,我希望当我想将一个函数的所有参数传递给另一个函数而不一一列出这些参数时,我可以使用match.call

示例:outer1 一个接一个地传递参数,outer2 使用 match.call

outer1 <- function(a, b, c) 
  inner1(a, b, c)


inner1 <- function(a, b, c)  
  return(a + b + c$first + c$second)


outer2 <- function(a, b, c) 
   mycall <- match.call()
   inner2(mycall)


inner2 <- function(call) 
   return(call$a + call$b + call$c$first + call$c$second)


outer1(1, 2, list(first = 3, second = 4)) # OK: 10
outer2(1, 2, list(first = 3, second = 4)) # OK: 10

第一个问题出现了,当-1而不是1被传递给outer2时:

outer2(-1, 2, list(first = 3, second = 4)) # Error in call$a + call$b : non-numeric argument to binary operator

问题1:传递-1而不是1有什么技术区别?我知道

typeof(quote(1)) # double
typeof(quote(-1)) # language

但我想我在第二种情况下传递了language 对象这一事实并不是(唯一)相关的区别,因为将某种类型的语言传递给参数c 有效(typeof(quote(list(first = 3, second = 4))) # language)。

为了克服上述问题,我尝试eval所有language类型的参数:

outer3 <- function(a, b, c) 

parsedCall <- lapply(match.call()[-1L], FUN=function(argument) 
    if(is.language(argument)) 
      return(eval(argument))
     else 
      return(argument)
    
  )

  inner3(parsedCall)


inner3 <- function(parsedCall)   
  return(parsedCall$a + parsedCall$b + parsedCall$c$first + parsedCall$c$second)


outer3(-1, 2, list(first = 3, second = 4)) # OK: 8

问题 2:outer3 中的方法似乎“有效”,但我还需要考虑其他陷阱吗? (我知道在某些情况下评估参数可能是不利的,但对我来说这不应该是一个问题。)

问题 3: 我想将所有参数传递给另一个函数的愿望并不少见。有没有比我做的更好/标准的方法?

问题 4: 将原始 call 传递给内部函数并在那里执行 eval 内容是否有利?如果我想将参数作为inner 函数中的局部变量(而不是parsedCall 列表的元素),这会有所帮助吗?然后,inner3 的主体可能与inner1 的主体相同(而在当前的解决方案中,我必须将a+b 替换为parsedCall$a + parsedCall$b)。

【问题讨论】:

请限制自己在每个帖子中回答一个问题。关于您的第一个问题:我相信-1 是对一元减函数的调用(参见help("-")),即相当于;`-`(1)(添加; 以正确呈现此问题)。1 不是函数调用, 但只是一个双精度值。(我不确定-1 是否会是函数调用而不用引号括起来。然后它可能会被解析为双精度值。) 感谢您对我的第一个问题的评论,Roland。关于“每个帖子一个问题”:当我写这个问题时,我想知道在一个问题中包含几个“子问题”是否可以,然后决定这样做,因为我所有的问题都与“主要问题”密切相关——事实上,他们只关注不同的方面。与此同时,我发现了一种不同的方法:获取所有评估参数的列表,并使用 do.call 将其传递给内部函数(请参阅:***.com/a/17244041/2706569)。 【参考方案1】:

关于你的问题:

我想将所有参数传递给另一个函数的愿望是 并不少见。有没有比我更好/标准的方法 有吗?

那么我会说这是一种更常见的传递参数的方式:

inner1 <- function(a, b, c)  
  return(a + b + c$first + c$second)


outer3 <- function(a, b, c) 
  mycall <- match.call()
  mycall[[1]] <- as.symbol("inner1") # use inner 1
  eval(mycall)


outer4 <- function(a, b, c) 
  .args <- as.list(match.call()[-1])
  do.call(inner1, .args)


outer3(-1, 2, list(first = 3, second = 4))
#R> [1] 8

outer4(-1, 2, list(first = 3, second = 4))
#R> [1] 8

【讨论】:

有趣,谢谢。您介意解释一下outer3outer4 中的方法之间的区别吗?从可读性的角度来看,我更喜欢outer4,但是否需要考虑技术差异? 我不敢说实话。如果不需要,它们似乎都不会评估参数,并且它们都将 parent.frame() 评估为环境。

以上是关于使用 match.call 将所有参数传递给其他函数的主要内容,如果未能解决你的问题,请参考以下文章

将数组中的所有值作为参数传递给函数

将一个函数的所有参数传递给另一个函数

将主要参数传递给 gui 库的 init 函数

如何将事件和其他参数传递给单击处理程序

如何将额外的额外参数传递给批处理文件?

如何将 url 参数传递给视图以供其他类函数和模板使用