如何解决R包中使用内部数据的R6Class出现对象未找到错误?
问题:R包中R6对象引用内部变量触发“对象未找到”错误
我按照Konrad Rudolph的建议将sysdata.R移至data-raw文件夹并重命名为DATASET.R,但问题根源不在此,而是由problem_R6.R中定义的R6对象导致的。
我正在学习R6,尝试创建一个简单的R6类,使其使用data-raw/DATASET.R生成的内部变量。示例包基于默认R包模板,仅包含三个自定义R文件:
1. data-raw/DATASET.R(生成内部变量)
internal_name <- "Eric" usethis::use_data(internal_name, internal = TRUE, overwrite = TRUE)
2. R/R6_Class_1.R(定义基础R6类)
#' @import R6 #' #' @noRd name <- R6::R6Class( classname = "name", private = list( target_name = NULL), public = list( initialize = \(text) { private$target_name <- text }, get_name = \() { private$target_name } ) )
3. R/problem_R6.R(定义问候类,触发错误)
#' @import R6 #' #' @noRd greeting <- R6::R6Class( classname = "greeting", private = list( name = name$new(text = internal_name) ), public = list( message = NULL, initialize = \() { self$message = "Hello! " }, greet = \() { paste0(self$message, private$name$get_name(), "!") } ) )
错误信息
清理并安装包时,收到如下错误:
Error in eval(exprs[i], envir) : object 'internal_name' not found Error: unable to load R code in package 'testingR6' Execution halted ERROR: lazy loading failed for package 'testingR6' * removing 'C:/Users/.../R/win-library/4.4/testingR6' * restoring previous 'C:/Users/H.../R/win-library/4.4/testingR6' Exited with status 1.
包结构
> fs::dir_tree() . ├── data-raw │ └── DATASET.R ├── DESCRIPTION ├── man ├── NAMESPACE ├── R │ ├── problem_R6.R │ ├── R6 Class 1.R │ └── sysdata.rda └── testingR6.Rproj
我确认sysdata.rda由DATASET.R生成,加载时internal_name确实存在,但不清楚报错原因,想知道如何修复让包能正常包含该R6对象。
解决方案
问题根源
R包加载时会先解析执行R/目录下的所有脚本,之后才会加载sysdata.rda中的内部变量。你原来的代码在定义R6类的阶段就直接执行了name$new(text = internal_name),此时internal_name还未被加载到包的命名空间中,因此触发“对象未找到”错误。
修改代码
将private$name的初始化逻辑从类定义阶段移到initialize方法中,确保在创建类实例时,内部变量已经加载完成:
修改后的R/problem_R6.R代码:
#' @import R6 #' #' @noRd greeting <- R6::R6Class( classname = "greeting", private = list( name = NULL # 先初始化为NULL,延迟初始化 ), public = list( message = NULL, initialize = \() { self$message = "Hello! " private$name = name$new(text = internal_name) # 在实例初始化时创建name对象 }, greet = \() { paste0(self$message, private$name$get_name(), "!") } ) )
验证
重新清理并安装包,此时创建greeting实例时就能正常访问internal_name,调用greet()方法会输出Hello! Eric!。
内容的提问来源于stack exchange,提问作者Grasshopper_NZ
相关产品推荐
相关产品推荐

