例如,假设我希望能够定义一个函数,该函数返回与第一个参数串联的赋值变量的名称:
a <- add_str("b")
a
# "ab"
上面示例中的函数如下所示:
add_str <- function(x) {
arg0 <- as.list(match.call())[[1]]
return(paste0(arg0, x))
}
但是函数的arg0行被替换为一行的行,该行将获取要分配的变量的名称(“a”),而不是函数的名称。
我已经尝试过将match.call和sys.call弄混了,但是我无法使它正常工作。这里的想法是在变量和函数结果上调用赋值运算符,因此它应该是函数调用的父调用。
最佳答案
我认为这并不是严格可行的,正如其他解决方案所解释的那样,合理的选择可能是Yosi的答案。
但是,我们可以从一些想法中获得乐趣,从简单开始,逐渐变得疯狂。
1-定义一个类似于的中缀运算符
`%<-add_str%` <- function(e1, e2) {
e2_ <- e2
e1_ <- as.character(substitute(e1))
eval.parent(substitute(e1 <- paste0(e1_,e2_)))
}
a %<-add_str% "b"
a
# "ab"
2-重新定义
:=
,以便通过..lhs()
函数将lhs的名称提供给rhs我认为这是我最喜欢的选择:
`:=` <- function(lhs,rhs){
lhs_name <- as.character(substitute(lhs))
assign(lhs_name,eval(substitute(rhs)), envir = parent.frame())
lhs
}
..lhs <- function(){
eval.parent(quote(lhs_name),2)
}
add_str <- function(x){
res <- paste0(..lhs(),x)
res
}
a := add_str("b")
a
# [1] "ab"
可能有一种基于此方法重新定义
<-
的方法,但是由于递归问题,我无法弄清楚。3-使用内存地址暗黑魔法来搜寻lhs(如果存在)
这直接来自:Get name of x when defining `(<-` operator
为此,我们需要更改语法并定义函数
fetch_name
,该函数可以从*<-
函数获取rhs的名称,其中as.character(substitute(lhs))
将返回"*tmp*"
。fetch_name <- function(x,env = parent.frame(2)) {
all_addresses <- sapply(ls(env), pryr:::address2, env)
all_addresses <- all_addresses[names(all_addresses) != "*tmp*"]
all_addresses_short <- gsub("(^|<)[0x]*(.*?)(>|$)","\\2",all_addresses)
x_address <- tracemem(x)
untracemem(x)
x_address_short <- tolower(gsub("(^|<)[0x]*(.*?)(>|$)","\\2",x_address))
ind <- match(x_address_short, all_addresses_short)
x_name <- names(all_addresses)[ind]
x_name
}
`add_str<-` <- function(x,value){
x_name <- fetch_name(x)
paste0(x_name,value)
}
a <- NA
add_str(a) <- "b"
a
4-后者的一种变体,使用
.Last.value
:add_str <- function(value){
x_name <- fetch_name(.Last.value)
assign(x_name,paste0(x_name,value),envir = parent.frame())
paste0(x_name,value)
}
a <- NA;add_str("b")
a
# [1] "ab"
操作不必排在同一行,但它们需要彼此跟随。
5-还是一种变体,使用打印方法hack
极其肮脏和令人费解的,请取悦被折磨的精神,并诱骗其他人。
这是唯一真正提供预期输出的设备,但仅在交互模式下有效。
诀窍在于,除了执行第一个操作中的所有工作之外,我还使用第二个(打印)操作。因此,在第一步中,我返回一个值为
"b"
的对象,但我还为它分配了一个"weird"
类和一个打印方法,然后该打印方法修改该对象的值,重置其类并破坏自身。add_str <- function(x){
class(x) <- "weird"
assign("print.weird", function(x) {
env <- parent.frame(2)
x_name <- fetch_name(x, env)
assign(x_name,paste0(x_name,unclass(x)),envir = env)
rm(print.weird,envir = env)
print(paste0(x_name,x))
},envir = parent.frame())
x
}
a <- add_str("b")
a
# [1] "ab"
(a <- add_str("b")
将具有与以上两行相同的效果。 print(a <- add_str("b"))
也将具有相同的效果,但也将在非交互式代码中工作。