【问题标题】:How to assign a quosure to another object?如何将quosure分配给另一个对象?
【发布时间】:2021-05-02 08:26:56
【问题描述】:

我想更改一些参数的名称。

the guidelines之后,我应该使用lifecycle::deprecate_warn,然后将旧名称赋予新名称。

但是,在我的函数中,参数通常与 quosures 一起使用,因此归因失败并出现错误:

library(tidyverse)
library(lifecycle)
library(rlang)
my_fun = function(df, cols, .vars = deprecated()){
  if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
    deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
    cols <- .vars #error is thrown here
  }
  select(df, {{cols}})
}

my_fun(iris, cols=Sepal.Length) %>% head()
#>   Sepal.Length
#> 1          5.1
#> 2          4.9
#> 3          4.7
#> 4          4.6
#> 5          5.0
#> 6          5.4
my_fun(iris, .vars=Sepal.Length) %>% head()
#> Warning: The `.vars` argument of `my_fun()` is deprecated as of <NA> 0.1.6.
#> Please use the `cols` argument instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_warnings()` to see where this warning was generated.
#> Error in my_fun(iris, .vars = Sepal.Length): objet 'Sepal.Length' introuvable

reprex package (v0.3.0) 于 2021-01-28 创建

我盲目地用enquo 和其他人尝试了各种东西,但没有任何效果。

如何将旧名称归于新名称?

【问题讨论】:

    标签: r rlang quosure


    【解决方案1】:

    回想一下{{!!enquo() 的简写。由于您要引用cols.vars,取决于缺少哪一个,我建议分别引用!!enquo()

    my_fun = function(df, cols, .vars = deprecated()){
      if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
        deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
        cols <- enquo(.vars)    # Quote .vars, if cols is missing
      }
      else cols <- enquo(cols)  # Quote cols, if cols is not missing
    
      select(df, !!cols)        # Unquote with !!, instead of {{, which is !!enquo()
    }
    
    my_fun(iris, cols=Sepal.Length) %>% head()    # Works
    my_fun(iris, .vars=Sepal.Length) %>% head()   # Also works
    

    如果您绝对必须使用{{,则修改捕获的表达式的唯一方法是更改​​函数的调用方式。这可以通过一点递归来完成(即,让my_fun 自己调用):

    my_fun = function(df, cols, .vars = deprecated()){
      if (quo_is_missing(enquo(cols)) && !quo_is_missing(enquo(.vars))) {
        deprecate_warn("0.1.6", "my_fun(.vars=)", "my_fun(cols=)")
        return( my_fun(df, {{.vars}}) )   # .vars will be captured as cols
      }
    
      select(df, {{cols}})
    }
    

    【讨论】:

    • 确实,这是我考虑过的解决方案。不幸的是,我并没有真正使用dplyr::select(),而是一个期望 quosure 的内部函数。它还需要一些有意义的重构来改变内部功能,所以我宁愿不这样做。
    • 对不起,它出来错了,我的意思是我的内部函数需要一个名字,而不是一个 quosure。就像dplyr::select
    • 对不起,最后一行必须是select(df, {{cols}}),这样才能模仿我的函数的工作方式。您的答案非常好,但是需要进行太多重构。如果没有其他解决方案,我会接受。
    • 不幸的是,{{ 对您想要做的事情过于严格。它捕获提供给cols 的表达式并立即使用它。由于两个动作之间没有间隙,因此没有可以修改表达式的地方。更改{{ 捕获的内容的唯一方法是修改my_fun 的调用方式,可能在包装器的帮助下。
    • 当然,这样的包装器可以是函数本身;)请看我的编辑。
    猜你喜欢
    • 2019-12-27
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    • 1970-01-01
    相关资源
    最近更新 更多