2015-10-19 50 views
3

我正在研究一个将字符串作为函数参数的R包。现在我想使用非标准评估来允许非字符串输入。另外,为了保持向后兼容性,我想保留函数接受字符串的可能性。如何编写也需要字符输入的NES函数?

Hadley给出example与子集功能,并建议每个NES函数应该伴随着一个标准的评估函数。

library(lazyeval) 
# standard evaluation 
subset2_ <- function(df, condition) { 
    r <- lazy_eval(condition, df) 
    r <- r & !is.na(r) 
    df[r, , drop = FALSE] 
} 

subset2_(mtcars, lazy(mpg > 31)) 


# NES can be written easily afterwards 

subset2 <- function(df, condition) { 
    subset2_(df, lazy(condition)) 
} 

虽然SE功能现在也需要引用输入,

subset2_(mtcars, "mpg > 31") 

的NSE函数抛出一个错误:

subset2(mtcars, "mpg > 31") 

但我希望用户具有相同的功能( NSE函数)用于引用和无引号的参数。

任何想法?

+0

我会添加另一个参数来区分这两种情况。即'with = FALSE'用于字符大小写'la'data.table'的方式。 – agstudy

回答

4

NSE功能需要NSE输入。这就是这种模式的重点,不是吗?

subset2(mtcars, mpg > 31) 

你当然也可以允许NSE功能采取字符输入,但我建议反对 - 强烈。不要混合使用SE和NSE,这样做没有优势,并且会混淆(并且可能存在错误,因为您在混合域)。

这就是说,当然以下工作:

subset2 <- function(df, condition) { 
    if (is.character(substitute(condition))) 
     subset2_(df, condition) 
    else 
     subset2_(df, lazy(condition)) 
} 

如果你想允许NSE和SE在向后兼容的原因相同的功能,我建议在未来的版本中逐步淘汰的SE版本,现在添加一个弃用警告。要添加弃用警告:

subset2 <- function(df, condition) { 
    if (is.character(substitute(condition))) { 
     msg = sprintf(paste0('Calling %s with a quoted expression is', 
          ' deprecated. Pass an unquoted expression', 
          ' instead, or use %s.'), 
         sQuote('subset2'), sQuote('subset2_')) 
     .Deprecated(msg = msg) 
     subset2_(df, condition) 
    } 
    else 
     subset2_(df, lazy(condition)) 
} 
+0

谢谢你。那么你会建议如何转换到NSE并保持向后兼容? – Marti

+0

@Marti啊,向后兼容性是一个很好的论点。为此的标准解决方案是发布一个主要的修订,其中旧行为已被弃用。在之后的* next *主版本中,旧行为被删除,从而打破了向后兼容性。 –

+0

我认为那就是要走的路。如果我在非引用表达式上使用is.character,它会引发错误。 '子集2中的错误(mtcars,mpg> 31):没有找到'mpg'对象' – Marti

相关问题