[英]Dynamically naming objects to be updated
I have defined an S4 Class with a slot that is a list.我已经定义了一个 S4 类,其中的插槽是一个列表。 I have written a method (based on Genolini's introduction to S4 - section 10.2) to append a new entry to that list:
我编写了一个方法(基于 Genolini 对 S4 的介绍 - 第 10.2 节)来向该列表附加一个新条目:
setClass("MyClass",
slots = c(entries = "list")
)
a1 <- new("MyClass", entries = list(1))
setGeneric(name="MyAppend",
def=function(.Object, newEntry)
{
standardGeneric("MyAppend")
}
)
setMethod(f = "MyAppend",
signature = "MyClass",
definition = function(.Object, newEntry){
nameObject <- deparse(substitute(.Object))
newlist <- .Object@entries
n <- newlist %>% length
newlist[[n + 1]] <- newEntry
.Object@entries <- newlist
assign(nameObject, .Object, envir = parent.frame())
return(invisible)
}
)
If I then run如果我然后跑
MyAppend(a1, 2)
a1
I get我得到
R>a1
An object of class "MyClass"
Slot "entries":
[[1]]
[1] 1
[[2]]
[1] 2
which is just as it should be.这是应该的。
But in my application I will be generating the names of the objects to be updated dynamically:但是在我的应用程序中,我将生成要动态更新的对象的名称:
ObjectName <- paste0("a", 1)
then I can turn that name into the object itself with然后我可以将该名称转换为对象本身
Object <- ObjectName %>% sym %>% eval
and then str(Object)
returns然后
str(Object)
返回
Formal class 'MyClass' [package ".GlobalEnv"] with 1 slot
..@ entries:List of 3
.. ..$ : num 1
.. ..$ : num 2
which, again, is just as it should be.这又是应该的。
But when I run但是当我跑
MyAppend(Object, 3)
Object
a1
I get the following that shows that while Object
has been updated a1
has not been.我得到以下信息,表明虽然
Object
已更新,但a1
尚未更新。
R>Object
An object of class "MyClass"
Slot "entries":
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
R>
R>a1
An object of class "MyClass"
Slot "entries":
[[1]]
[1] 1
[[2]]
[1] 2
What am I doing wrong, please?请问我做错了什么?
The problem is that this line:问题是这一行:
Object <- ObjectName %>% sym %>% eval
Doesn't do what you think it does.不会做你认为它会做的事情。 The right hand side evaluates to the object
a1
, so it is no different to doing右手边的计算结果为对象
a1
,所以它与做没有什么不同
Object <- a1
But this creates a copy of a1
, it does not create a reference or a pointer or a synonym for a1
.但是,这将创建的副本
a1
,它不会创建一个引用或指针或同义词a1
。
It is possible to create a reference (of sorts) by passing the unevaluated name of the object you wish to append to your generic method.这是可能通过传递要追加到您的泛型方法的对象的未计算名称创建(的种类)的参考。 If you leave out the
eval
part of ObjectName %>% sym %>% eval
then Object gets assigned the name a1
, which can be passed as a reference to the object a1
.如果省略
ObjectName %>% sym %>% eval
的eval
部分,则 Object 将被分配名称a1
,该名称可以作为对对象a1
的引用传递。
However, this leaves you with a new problem: MyAppend
doesn't know what to do with an object of class name
.然而,这给您带来了一个新问题:
MyAppend
不知道如何处理类name
的对象。 You therefore need to write a suitable method for dealing with names:因此,您需要编写一个合适的方法来处理名称:
setMethod(f = "MyAppend",
signature = "name",
definition = function(.Object, newEntry){
stopifnot(class(eval(.Object)) == "MyClass")
objname <- as.character(.Object)
.Object <- eval(.Object)
.Object@entries <- append(.Object@entries, newEntry)
assign(as.character(objname), .Object, envir = parent.frame())
}
)
Now let's see how this would work:现在让我们看看这是如何工作的:
a1 <- new("MyClass", entries = list(1))
a1
#> An object of class "MyClass"
#> Slot "entries":
#> [[1]]
#> [1] 1
MyAppend(a1, 2)
a1
#> An object of class "MyClass"
#> Slot "entries":
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
Object <- paste0("a", 1) %>% sym()
MyAppend(Object, 3)
a1
#> An object of class "MyClass"
#> Slot "entries":
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
#>
#> [[3]]
#> [1] 3
I think this was what you intended.我想这就是你的意图。 You may wish to consider having a method that dispatches character strings to make this workflow easier (you would use
get
inside the method to retrieve the object from the name passed as a character string)您可能希望考虑使用分派字符串的方法来简化此工作流程(您将在方法内部使用
get
从作为字符串传递的名称中检索对象)
Note that I altered your own function as well;请注意,我也更改了您自己的功能; you shouldn't do
return(invisible)
, since this returns the body of the built-in function invisible
.你不应该做
return(invisible)
,因为这会返回内置函数invisible
的主体。 Just leave the return statement out altogether.只需将 return 语句完全保留即可。 You can also make use of the built-in function
append
, to make your method for MyClass
a bit simpler:您还可以使用内置函数
append
,使您的MyClass
方法更简单一些:
setMethod(f = "MyAppend",
signature = "MyClass",
definition = function(.Object, newEntry){
nameObject <- deparse(substitute(.Object))
.Object@entries <- append(.Object@entries, newEntry)
assign(nameObject, .Object, envir = parent.frame())
}
)
As the accepted answer has mentioned, the line正如接受的答案所提到的,该行
Object <- ObjectName %>% sym %>% eval
does not function as you intend.无法按预期运行。
If you want to work with dynamically generated names, the two functions you need to use are get
(get an object associated with a name) and assign
(assign into an object whose name you compute).如果您想使用动态生成的名称,您需要使用的两个函数是
get
(获取与名称关联的对象)和assign
(分配给您计算名称的对象)。 Both have comprehensive help pages.两者都有全面的帮助页面。
Pretty much nothing else will work (except for eval(parse(text=paste0(...)))
but that is not recommended programming practice for a number of reasons.几乎没有其他方法可以工作(除了
eval(parse(text=paste0(...)))
但由于多种原因,这不是推荐的编程实践。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.