【问题标题】:Why doesn't forwarding work in this case?为什么在这种情况下转发不起作用?
【发布时间】:2023-03-17 10:14:01
【问题描述】:

我在 R 中转发“...”时遇到了一些麻烦。
我找到了解决方案,但我仍然不明白为什么我的原始代码不正确。也许有人可以向我解释一下?

我准备了一个reprex:

# modify a string with glue.
# z is an optional argument
fun_A <- function(my_string, ..., z = NULL){
  print(paste0("z value: ", as.character(z))) # do something with z here
  print(list(...)) # to test: print ... to check that all variables are still there

  my_string <- glue::glue(my_string, ...)
  my_string
}

# when fun_A() is used inside fun_B, 'z' must be filled with the same value in fun_A() and fun_B().
fun_B <- function(z, my_string, ...){
  my_string_mod <- rlang::enquo(my_string) %>%
    rlang::call_modify(z = z) %>%
    rlang::eval_tidy()
  my_string_mod
  # then other stuff, useless for the reprex
}

# calls fun_B() but for a specific string, now the argument of my_string are explicit.
fun_C_ok <- function(x, y){
  fun_B(z = "i am z",
        my_string = fun_A(my_string = "replace {x} and {y}.",
                          x = !!x, y = !!y)
  )

一切如我所愿:

fun_A() 中,“z”按预期缺失。 'x' 和 'y' 已按预期更改

> fun_A(my_string = "replace {x} and {y}.", x = "this", y = "that")
[1] "z value: "
$x
[1] "this"

$y
[1] "that"

replace this and that.

fun_B() 中,'z' 在 fun_A() 中按预期进行了修改。 'x' 和 'y' 已按预期更改

> fun_B(z = "i am z", my_string = fun_A(my_string = "replace {x} and {y}.", x = "this", y = "that"))
[1] "z value: i am z"
$x
[1] "this"

$y
[1] "that"

replace this and that.

fun_C_ok() 中,'z' 在 fun_A() 中按预期进行了修改。 'x' 和 'y' 已按预期更改

> fun_C_ok(x = "this", y = "that")
[1] "z value: i am z"
$x
[1] "this"

$y
[1] "that"

replace this and that.

一开始,我这样写最后一个函数(没有bang-bang操作符(!!))

fun_C_notok <- function(x, y){
  fun_B(z = "i am z",
        my_string = fun_A(my_string = "replace {x} and {y}.",
                          x = x, y = y)
  )
}

它不起作用,gluefun_A() 中找不到“x”,但我不明白为什么,因为“x”和“y”存在于列表中(...)

> fun_C_notok(x = "this", y = "that")

[1] "z value: i am z"
$x
[1] "this"

$y
[1] "that"

 Error in eval(parse(text = text, keep.source = FALSE), envir) : 
  object 'x' not found 

11. eval(parse(text = text, keep.source = FALSE), envir) 
10. eval(parse(text = text, keep.source = FALSE), envir) 
9. .transformer(expr, env) 
8. (function (expr) 
{
    eval_func <- .transformer(expr, env)
    tryCatch(as.character(eval_func), error = function(e) { ... 
7. glue_data(.x = NULL, ..., .sep = .sep, .envir = .envir, .open = .open, 
    .close = .close, .na = .na, .transformer = .transformer, 
    .trim = .trim) 
6. glue::glue(my_string, ...) 
5. fun_A(my_string = "replace {x} and {y}.", x = x, y = y, z = "i am z") 
4. rlang::eval_tidy(.) 
3. rlang::enquo(my_string) %>% rlang::call_modify(z = z) %>% rlang::eval_tidy() 
2. fun_B(z = "i am z", my_string = fun_A(my_string = "replace {x} and {y}.", 
    x = x, y = y)) 
1. fun_C_notok(x = "this", y = "that") 

有人明白为什么 glue()fun_C_notok() 中找不到 'x' 吗??

【问题讨论】:

  • 我认为这很可能是 glue::glue 或其使用的功能之一中的错误。如果您查看该回溯,您会发现它正在做非常复杂的事情,并且他们可能做出了一个在您的示例中不成立的假设,例如传递给它的变量可以在调用者框架中进行评估,而不是在您的示例中其父级。
  • 刚刚尝试了使用rgl:::subst 内部函数而不是glue::glue 的示例,它工作正常。 subst() 需要字符串为"replace %x% and %y%.",但可以用作funA 中的直接替换。
  • 感谢您的回答。我已经在胶水 github 中询问了它是否是一个错误。

标签: r ellipsis


【解决方案1】:

我很确定这是glue 中的一个错误,这里建议修复:https://github.com/tidyverse/glue/issues/231#issuecomment-951129873。与此同时,这似乎可行:通过将funA 修改为此明确指定环境:

fun_A <- function(my_string, ..., z = NULL){
  print(paste0("z value: ", as.character(z))) # do something with z here
  print(list(...)) # to test: print ... to check that all variables are still there

  e <- list2env(list(...))
  my_string <- glue::glue(my_string, .envir = e, ...)
  my_string
}

【讨论】:

    猜你喜欢
    • 2017-11-26
    • 2010-12-29
    • 1970-01-01
    • 2021-08-05
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多