r-使用引号以编程方式创建S3通用



我想通过函数在全局环境中创建一个s3通用。我看了R.methodsS3::setGenericS3.default,并提出了以下内容:

create_generic <- function(nm) {
  src <- sprintf("%s <- function(obj, ...) UseMethod("%s")", nm, nm)
  expr <- parse(text = src)
  print(expr)
  eval(expr, env = .GlobalEnv)
}
create_generic("cat")
#> expression(cat <- function(obj, ...) UseMethod("cat"))
cat
#> function (obj, ...) 
#> UseMethod("cat")

这有效,我希望它能做到。但是,我一直在尝试使用引号进行这项工作,但我被困了:

library(rlang)
create_generic2 <- function(nm) {
  expr <- expr(!!sym(nm) <- function(obj, ...) UseMethod(!!nm))
  print(expr)
  eval(expr, env = .GlobalEnv)
}
create_generic2("dog")
#> dog <- function(obj, ...) UseMethod("dog")
dog
#> function(obj, ...) UseMethod(!!nm)

这是我熟悉的tidyeval,因为我想看看基本r。

的样子

我对create_generic中没有字符串操作的任何版本都感兴趣。

base r:

create_generic <- function(fun_name) {
  new_fun <- function(obj, ...) UseMethod(fun_name)
  assign(fun_name, new_fun, envir = .GlobalEnv)
}
cat("hin")
# hi
create_generic("cat")
cat("hin")
# Error in UseMethod(fun_name) : 
#   no applicable method for 'cat' applied to an object of class "character"
cat.character <- base::cat
cat("hin")
# hi

您也可以使用expr_interp()在功能中使用未引用的操作员:

create_generic <- function(name, env = globalenv()) {
  gen <- expr_interp(function(obj, ...) {
    UseMethod(!!name)
  })
  environment(gen) <- env
  assign(name, gen, envir = env)
}

前缀是 expr_,因为它(内部)比表达式包装器(例如公式和功能。

最新更新