R 如何找到 S3 方法?为什么 R 找不到我的 S3 `+` 方法?

How does R find S3 methods? Why can't R find my S3 `+` method?

我想创建 attach 一个包含 S3 方法的 environment 并让 R 在搜索路径中找到它们,使用方法名称 (即,我应该能够让 infix-style a + b 工作而不必写 prefix-style "+.Foo"(a, b)).我究竟做错了什么?虽然有点长,但我可以在合理的时间内想出的最短的例子如下。评论详细说明了情况和问题。

更新:我已根据所选答案附加了一些代码。

# **** CLEAR THE USER WORKSPACE / GLOBAL ENVIRONMENT ****
rm(list = ls( all = TRUE ))

# **** RESET THE SEARCH PATH. (I'VE NEVER HAD AN R INSTALLATION THAT DOESN'T BOOT ****
# **** WITH package:stats AS THE SECOND-TO-LAST ITEM ON THE SEARCH PATH.)                   ****
while (search()[[2]] != "package:stats") detach()

search ()
# [1] ".GlobalEnv" "package:stats" "package:graphics" "package:grDevices" "package:utils"
# [6] "package:datasets" "package:methods" "Autoloads" "package:base"     

x <- 1L
class (x) <- "Foo"

`+.Foo` <- function ( x , y ) {
    cat("This is `x.Foo`\n")
    # "non-standard" addition on purpose
    z <- -1L * ( as.integer(x) + as.integer(y) )
    class(z) <- "Foo"
    z }

x + x
# This is `x.Foo`
# [1] -2
# attr(,"class")
# [1] "Foo"

# Note that R finds `x.Foo` in the global environment.

FooEnv <- new.env(parent = as.environment(search()[[2]]))
attr(FooEnv, "name") <- "FooEnv"
FooEnv
# <environment: 0xhhhhhhhhhhhhhhhh> ## Each h is a hex-digit.
# attr(,"name")
# [1] "FooEnv"

parent.env(FooEnv)
# <environment: package:stats>
# attr(,"name")
# [1] "package:stats"
# attr(,"path")
# [1] "C:/Program Files/R/R-4.0.3/library/stats"

# The path above will vary with the R installation.

# I want the next 3 lines of R code is to replace `+.Foo` in the global environment
# with `x.Foo` on the search path.
FooEnv $ `+.Foo` <- `+.Foo`
rm(`+.Foo`)
attach(what = FooEnv, name = attr(FooEnv, "name"))

search()
# [1] ".GlobalEnv" "FooEnv" "package:stats" "package:graphics" "package:grDevices"
# [6] "package:utils" "package:datasets" "package:methods" "Autoloads" "package:base"    

x + x
# [1] 2
# attr(,"class")
# [1] "Foo"

## Note lack of "This is `x.Foo`".
## Note the sign.
## This is not the `+` we're looking for.

# `methods` finds `+.Foo`:
methods("+")
# [1] +.Date +.Foo +.POSIXt
# see '?methods' for accessing help and source code

# `find` finds `+.Foo`
find("+.Foo")
# [1] "FooEnv"

# Although the following works, I want to call `x.Foo` using infix style.
`+.Foo`(x, x)
# This is `x.Foo`
# [1] -2
# attr(,"class")
# [1] "Foo"

write.dcf(R.Version())
# platform: x86_64-w64-mingw32
# arch: x86_64
# os: mingw32
# system: x86_64, mingw32
# status:
# major: 4
# minor: 0.3
# year: 2020
# month: 10
# day: 10
# svn rev: 79318
# language: R
# version.string: R version 4.0.3 (2020-10-10)
# nickname: Bunny-Wunnies Freak Out

# `.S3method` seems to do the trick. Acknowledgement: @MrFlick
.S3method("+", "Foo")
x + x
# This is `x.Foo`
# [1] -2
# attr(,"class")
# [1] "Foo"

如果您没有将 S3 方法注册为包命名空间的一部分或在全局环境中,则需要使用 .S3method() 函数显式注册它。所以在这种情况下你会做

.S3method("+", "Foo", FooEnv$`+.Foo`)

这里进一步讨论了这个问题:https://developer.r-project.org/Blog/public/2019/08/19/s3-method-lookup/