使用引用以编程方式创建 S3 泛型
Using quotation to programmatically create a S3 generic
我想通过一个函数在全局环境中创建一个 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
,因为那是我所熟悉的,但我想看看它在 base R 中的样子。
我对在 create_generic
中没有字符串操作的任何版本感兴趣。
在基数 R 中:
create_generic <- function(fun_name) {
new_fun <- function(obj, ...) UseMethod(fun_name)
assign(fun_name, new_fun, envir = .GlobalEnv)
}
cat("hi\n")
# hi
create_generic("cat")
cat("hi\n")
# Error in UseMethod(fun_name) :
# no applicable method for 'cat' applied to an object of class "character"
cat.character <- base::cat
cat("hi\n")
# 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_
因为它是(内部)通用的表达式包装器,例如公式和函数。
我想通过一个函数在全局环境中创建一个 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
,因为那是我所熟悉的,但我想看看它在 base R 中的样子。
我对在 create_generic
中没有字符串操作的任何版本感兴趣。
在基数 R 中:
create_generic <- function(fun_name) {
new_fun <- function(obj, ...) UseMethod(fun_name)
assign(fun_name, new_fun, envir = .GlobalEnv)
}
cat("hi\n")
# hi
create_generic("cat")
cat("hi\n")
# Error in UseMethod(fun_name) :
# no applicable method for 'cat' applied to an object of class "character"
cat.character <- base::cat
cat("hi\n")
# 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_
因为它是(内部)通用的表达式包装器,例如公式和函数。