简体   繁体   English

动态命名要更新的对象

[英]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 %>% evaleval部分,则 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM