代码之家  ›  专栏  ›  技术社区  ›  cdeterman

S4方法在另一个包中设置时失败

s4 r
  •  7
  • cdeterman  · 技术社区  · 8 年前

    当我试图设置另一个包中也定义的方法时,遇到了一个奇怪的问题。可以找到一个演示此问题的示例包 here .

    关键是 typeof 我尝试设置的方法。我用 setMethod 功能 类型 当我构建包并在一个简单的s4类上尝试它时,它就工作了。

    x <- new("A", x = 2)
    typeof(x)
    [1] "typeof was called"
    [1] "myClassA"
    

    但是,如果我加载另一个以前也设置了 类型 (例如 bigmemory )在装载之前 s4test 如果直接调用它,它将继续正常工作。

    library(bigmemory)
    library(s4test)
    x <- new("A", x = 2)
    typeof(x)
    [1] "typeof was called"
    [1] "myClassA"
    

    但是,如果 类型 方法在内部由另一个方法调用(例如 nrow 看见 here )然后它失败了,只会回来 S4

    nrow(x)
    [1] "A"
    attr(,"package")
    [1] "s4test"
    Function: typeof (package base)
    x="ANY"
    x="big.matrix"
    x="myClass"
    
    A connection with                      
    description "stdout"  
    class       "terminal"
    mode        "w"       
    text        "text"    
    opened      "opened"  
    can read    "no"      
    can write   "yes"     
    [1] "S4"
    
    2 回复  |  直到 8 年前
        1
  •  2
  •   Alexis    8 年前

    胡安·安东尼奥走在正确的轨道上, 但这与 Depends 和 Imports .

    答案在文档条目中 Methods_for_Nongenerics (适用于 typeof 因为它不是 base ):

    在为r包编写方法时,这些方法通常应用于在该包中不是泛型的函数(在另一个包中);也就是说,在其自己的包中没有用于该函数的形式化方法,尽管它可能有s3方法。本例中的编程涉及一个额外的步骤,即调用setGeneric()来声明函数在包中是泛型的。

    调用包中的函数将使用在其中定义的所有方法或创建相同泛型函数的任何其他加载的包。类似地,对这些包中函数的调用将使用您的方法。

    然而,原始版本仍然是非通用的。调用该包或使用该版本的其他包将 不 派遣你的方法,除了特殊情况…

    通过在干净的r会话中运行以下命令,可以看到此操作的效果:

    environment(typeof)
    <environment: namespace:base>
    
    library(s4test)
    environment(typeof)
    <environment: 0x0000000017ca5e58>
    

    装好包裹后, 这个 类型 函数已成为泛型, 但不是原来的环境。 你还可以看到 围住 新通用环境的环境:

    parent.env(environment(typeof))
    <environment: namespace:base>
    

    调用函数时, 先看看现在的环境, 当找不到东西时,在封闭的环境中查找。 这个 nrow 功能是 基础 包裹 (它也不是普通的, 虽然这里不相关, 这意味着它将发现自己的非泛型 类型 在看到普通的那个之前。

    文献资料 非泛化方法 解释不同的场景, 但对你来说, 实际上,您可以执行以下操作:

    setMethod('nrow', signature(x="myClass"),
              function(x) {
                  # find the generic version from the global environment and bind it here
                  typeof <- get("typeof", .GlobalEnv)
                  switch(typeof(x),
                         "myClassA" = "A rows",
                         "myClassB" = "B rows")
              }
    )
    
    nrow(x)
    [1] "typeof was called"
    [1] "A rows"
    
        2
  •  0
  •   Juan Antonio Roldán Díaz    8 年前

    问题是 Depends 并不总是确定。 Imports 比使用更安全 取决于 ,您可以阅读更多关于此的信息 here .

    在全局环境中,您的包使用BigMealth::Type和内部NoRealBase::Type。

    > base::typeof(x)
    [1] "S4"
    > bigmemory::typeof(x)
    [1] "typeof was called"
    [1] "myClassA"
    

    您可以通过直接引用要使用的包名称的函数来解决此问题。

    推荐文章