我正在开发一个 R 包,该包具有许多函数,这些函数遵循非 R 标准做法,即修改作为参数传入的对象。这通常可以正常工作,但当要修改的对象在列表中时会失败。
给出赋值形式示例的函数:
myFun<-function(x){
xn <- deparse(substitute(x))
ev <- parent.frame()
# would do real stuff here ..
# instead set simple value to modify local copy
x[[1]]<-"b"
# assign in parent frame
if (exists(xn, envir = ev))
on.exit(assign(xn, x, pos = ev))
# return invisibly
invisible(x)
}
这有效:
> myObj <-list("a")
> myFun(myObj)
> myObj
[[1]]
[1] "b"
但如果对象是列表的成员,它就不起作用:
> myObj <-list("a")
> myList<-list(myObj,myObj)
> myFun(myList[[1]])
> myList
[[1]]
[[1]][[1]]
[1] "a"
[[2]]
[[2]][[1]]
[1] "a"
在这里阅读其他问题的答案后,我看到文档assign
清楚地说明:
assign does not dispatch assignment methods, so it cannot be used to set elements of vectors, names, attributes, etc.
由于存在使用这些函数的现有代码库,我们不能放弃就地修改语法。是否有人对修改作为父框架中列表成员的对象的解决方法或替代方法有建议?
更新:
我考虑过尝试推出自己的分配功能,例如:
assignToListInEnv<-function(name,env,value){
# assume name is something like "myList[[1]]"
#check for brackets
index<-regexpr('[[',name,fixed=TRUE)[1]
if(index>0){
lname<-substr(name,0,index-1)
#check that it exists
if (exists(lname,where=env)){
target<-get(lname,pos=env)
# make sure it is a list
if (is.list(target)){
eval(parse(text=paste('target',substr(name,index,999),'<-value',sep='')))
assign(lname, target, pos = env)
} else {
stop('object ',lname,' is not a list in environment ',env)
}
} else {
stop('unable to locate object ',lname,' in frame ',env)
}
}
}
但它看起来很脆弱,需要处理更多的情况($
以及) [
,[[
并且可能仍然会失败,[[x]]
因为x
会在错误的框架中进行评估......