我正在研究一个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]]
可能仍会失败,因为{ {1}}将在错误的框架中进行评估......