R6传递一个self $ FUN作为参数

问题描述

我开始构建“用户友好”的R6类,并希望使函数完成我的类的大部分工作。到目前为止,这是我的结构

x <- X$new()
veggie_cubes <- veggie %>% x$cubesX(ID)
veggie_slices <- veggie %>% x$sliceX(ID)

我的问题是,现在是否可以重写代码,例如:

x <- X$new()
veggie_cubes <- veggie %>% x$cutX(cubesX,ID)
veggie_slices <- veggie %>% x$cutX(sliceX,ID)

函数头应该看起来像:cut(.data,FUN,KEY)

到目前为止,我的想法是像这样写cut

cutX= function(.data,KEY)
{
   .data %>%
     FUN({{ KEY }}) %>%
     base::return()
}

唯一可行的方法调用veggie %>% x$cutX(x$cubesX,ID),我不太喜欢将其用作“用户友好”解决方案,我也不很喜欢为此使用字符串。有没有写x$方法

这是简化的R6类:

X <- R6::R6Class(
  classname = "X",public = base::list(
    cubesX = function(.data,KEY)
    {
      .data %>% 
        dplyr::select(!{{ KEY }}) %>% 
        base::return()
    },sliceX = function(.data,KEY)
    {
      .data %>% 
        dplyr::select({{ KEY }}) %>% 
        base::return()
    },cutX = function(.data,KEY)
    {
      .data %>% 
        FUN( {{ KEY}}) %>% 
        base::return()
    }
  )
)

运行示例:

x <- X$new()
iris %>% x$sliceX(Species)
iris %>% x$cubesX(Species)
# with FUN
iris %>% x$cutX(x$sliceX,Species)
iris %>% x$cutX(x$cubesX,Species)

未运行:

iris %>% x$cutX(sliceX,Species)
iris %>% x$cutX(cubesX,Species)

预先感谢:-)

解决方法

以下实现将允许您通过三种方法中的任何一种来调用函数。它通过使用非标准评估来确定FUN的格式为x$func还是仅使用裸func来工作。无论哪种情况,它都使用裸函数名称并构建一个调用以将其转换为self$func。然后,它只是对该函数求值。

因此,以下R6类在所有测试示例中均按预期工作:

X <- R6::R6Class(
  classname = "X",public = base::list(
    cubesX = function(.data,KEY)
    {
      .data %>% 
        dplyr::select(!{{ KEY }}) %>% 
        base::return()
    },sliceX = function(.data,KEY)
    {
      .data %>% 
        dplyr::select({{ KEY }}) %>% 
        base::return()
    },cutX = function(.data,FUN,KEY)
    {
      if(is.call(substitute(FUN))) {
        FUN <- substitute(FUN) 
        FUN[[2]] <- quote(self)
      }
      else 
        FUN <- as.call(list(quote(`$`),quote(self),substitute(FUN)))
 
      eval(as.call(list(FUN,quote(.data),substitute(KEY))))
    }
  )
)

例如,

x <- X$new()
iris %>% x$cutX(sliceX,Species)

#>        Species
#> 1       setosa
#> 2       setosa
#> 3       setosa
#> 4       setosa
#> 5       setosa
#> 6       setosa
#> 7       setosa
#> 8       setosa
#> 9       setosa
#> 10      setosa
#> 11      setosa
#> 12      setosa
#> 13      setosa
#> 14      setosa
#> 15      setosa
#> 16      setosa
#> 17      setosa
#> 18      setosa
#> 19      setosa
#> 20      setosa
#> ...etc