为何R对rdeckControls对象调度S3父类as.tags方法而非子类方法
问题原因解释
这个现象的核心是S3方法的可见性规则,具体逻辑如下:
- rdeck.controls包中的
as.tags.rdeckControls是未导出的内部方法:你调用methods("as.tags")的结果里,带*后缀的方法都属于非导出方法,as.tags.rdeckControls虽未标记*但实际也属于包内部方法,泛型函数默认不会访问未导出的包内部方法。 - sloop的
s3_dispatch只是静态匹配类名和方法名,不会验证方法是否可被泛型访问,所以它显示会匹配as.tags.rdeckControls,但实际运行时R的调度逻辑会跳过不可访问的方法。 - 当泛型
htmltools::as.tags找不到可调用的as.tags.rdeckControls时,会自动沿对象的类属性向量向后匹配,下一个类是htmlwidget,对应的as.tags.htmlwidget是htmlwidgets包导出的公开方法,所以实际调用了这个方法,触发了CSS单位校验的报错。 - 你直接调用
as.tags.rdeckControls(foo_widget)能正常运行,是因为手动调用时R允许访问已加载包的内部方法;你在本地环境自定义同名方法后调度正常,是因为全局环境的方法优先级最高,泛型可以直接访问。
验证方法
你可以运行以下代码确认方法的可见性:
# 检查泛型能否找到rdeckControls对应的方法,返回NULL代表不可访问 getS3method("as.tags", "rdeckControls", optional = TRUE) # 手动访问包内部方法是存在的,返回TRUE exists("as.tags.rdeckControls", asNamespace("rdeck.controls"))
解决办法
要让泛型正常调度as.tags.rdeckControls,可以手动注册这个S3方法:
registerS3method( "as.tags", "rdeckControls", rdeck.controls:::as.tags.rdeckControls )
如果长期使用,可以告知rdeck.controls包的开发者,在包的NAMESPACE文件中导出这个S3方法即可。
内容的提问来源于stack exchange,提问作者MilesMcBain
相关产品推荐
相关产品推荐

