在白皮书中引入的 S3 对象系统的核心是,(S3)方法是遵循 GEN.CLS
命名约定的普通函数(以 GEN.default
作为最终后备)。在这个对象系统的初始 R 实现中,这些方法是在调用泛型的环境(和所有封闭环境)中搜索的。
随着命名空间的出现(参见 Tierney (2003),“R 的名称空间管理”,R News,3(1):2-6),通过 NAMESPACE
文件中的 S3method()
指令注册 S3 方法的机制被添加进来。使用 S3method(GEN, CLS)
或 S3method(GEN, CLS, FUN)
分别为函数命名,GEN.CLS
或 FUN
无需导出即可分派。使用后者(3 个参数)指令可以绕过 GEN.CLS
命名约定。注册中使用的泛型是“从包中看到的”,因此需要在加载命名空间时提供。此注册机制适用于所有包(因为它们都有一个命名空间),但不适用于脚本代码(包外部)。
最初,只有在调用环境中找不到合适的方法时,才会查询 S3 注册表。基本方法传统上都遵循 GEN.CLS
命名约定,因此未注册,因为它们可以在 .BaseNamespaceEnv
中找到,作为包命名空间环境的静态部分的最后一个元素,因此位于从全局环境(.GlobalEnv
,用户的 workspace)开始并以基本环境(.BaseEnv
)结束的搜索路径之前。但是,所有已注册的方法都可以在附加包中被 GEN.CLS
导出(在注册表之前的搜索路径上找到)所掩盖。为了使 S3 查找更加安全和高效,在 R 3.5.0 中进行了更改,以便在调用环境的顶级环境(参见 ?topenv
)之后使用注册表。同时,基本中的所有 S3 方法现在也已注册。
自 R 3.6.0 起,NAMESPACE
中的 S3method()
指令也可用于执行延迟 S3 方法注册。使用 S3method(PKG::GEN, CLS, FUN)
函数 FUN
将仅在加载 PKG
的命名空间时才注册为包 PKG
的类 CLS
和泛型 GEN
的 S3 方法。这可用于处理不需要“立即”的情况,并且为了执行立即注册而必须预先加载 pkg
的命名空间(及其所有强依赖项)被认为“代价太大”。
自 trunk 中的 c76951(于 2019-08-10 提交)以来,有一个 .S3method()
函数用于在脚本中注册 S3 方法。同样,这允许以不同于 GEN.CLS
的名称注册方法。
通过所有这些注册增强功能,不再需要通过搜索路径(位于 .GlobalEnv
和 .BaseEnv
之间)查找 S3 方法,因此,trunk 中的 c77043(于 2019-08-19 提交)默认情况下已关闭。目前可以通过一个内部环境变量来控制,该变量最终会消失,因为依赖于此类中间搜索路径查找既不安全又低效。这似乎是一个重大更改:但事实上,CRAN 常规检查已在一年多前关闭了中间搜索路径查找,并且所有源于此更改的检查问题早已消除。类似地,Bioconductor 将在即将发布的 3.10 版中为其软件包添加所有缺少的 S3 方法注册。