如何实现R6类的序列化及本地保存、加载功能
R6实例持久化通用实现方案
核心利用R6的反射能力动态读取实例字段,无需硬编码字段名,父类实现后所有子类可直接继承复用。
完整实现代码
library(R6) # 可选:用jsonlite做JSON序列化,也可以直接用R原生rds格式 library(jsonlite) # 可序列化基础父类 SerializableR6 <- R6Class( "SerializableR6", public = list( # 序列化实例到磁盘 save = function(path, use_rds = FALSE) { # 动态收集所有非方法的公共字段 public_fields <- setdiff(names(self), ls(self$.__enclos_env__$private)) public_fields <- Filter(function(f) !is.function(self[[f]]), public_fields) public_vals <- setNames(lapply(public_fields, function(f) self[[f]]), public_fields) # 动态收集所有非方法的私有字段,不需要可删除本段 private_fields <- names(self$.__enclos_env__$private) private_fields <- Filter(function(f) !is.function(private[[f]]), private_fields) private_vals <- setNames(lapply(private_fields, function(f) private[[f]]), private_fields) # 组装序列化数据,保留类名用于恢复 serial_data <- list( class_name = class(self)[1], public = public_vals, private = private_vals ) # 支持两种存储格式 if (use_rds) { saveRDS(serial_data, path) } else { write_json(serial_data, path, auto_unbox = TRUE, digits = NA) } invisible(TRUE) } ) ) # 给父类添加静态加载方法,用于恢复实例 SerializableR6$set("public", "load", function(path, use_rds = FALSE) { # 读取序列化数据 serial_data <- if (use_rds) readRDS(path) else read_json(path, simplifyVector = TRUE) # 校验类是否已加载 if (!exists(serial_data$class_name)) { stop(sprintf("R6类 %s 未定义,请先加载类定义", serial_data$class_name)) } target_class <- get(serial_data$class_name) # 初始化空实例,类如果有必填初始化参数,可将初始化参数也存入serial_data后传入$new() instance <- target_class$new() # 恢复公共字段 for (field in names(serial_data$public)) { instance[[field]] <- serial_data$public[[field]] } # 恢复私有字段 for (field in names(serial_data$private)) { instance$.__enclos_env__$private[[field]] <- serial_data$private[[field]] } return(instance) }, overwrite = TRUE)
使用示例
所有子类只需继承SerializableR6即可自动获得持久化能力,无需额外编码:
# 自定义子类 Order <- R6Class( "Order", inherit = SerializableR6, public = list( order_id = NULL, amount = NULL, create_time = NULL, initialize = function(order_id, amount) { self$order_id <- order_id self$amount <- amount self$create_time = Sys.time() } ), private = list( # 私有字段也会自动序列化 user_id = "u_12345" ) ) # 测试流程 # 1. 创建实例 order1 <- Order$new("ord_001", 299.9) # 2. 保存为JSON格式 order1$save("order.json") # 3. 保存为RDS格式(性能更高,适合复杂数据) order1$save("order.rds", use_rds = TRUE) # 4. 从JSON恢复 order_from_json <- SerializableR6$load("order.json") # 5. 从RDS恢复 order_from_rds <- SerializableR6$load("order.rds", use_rds = TRUE)
适配优化方案
- 性能优先场景:优先使用RDS格式存储,比JSON序列化快3~10倍,且能完美保留所有R原生数据类型,无需做类型转换。
- 敏感字段过滤:在save方法的字段收集阶段添加过滤逻辑即可,例如
public_fields <- setdiff(public_fields, c("temp_cache", "access_token"))。 - 嵌套R6实例支持:如果字段包含其他R6实例,只需让嵌套类也继承
SerializableR6,在save阶段递归序列化、load阶段递归反序列化即可支持。 - 复杂初始化兼容:如果子类
initialize方法有必填参数,可将初始化参数也存入serial_data,加载时传入target_class$new()即可。
内容的提问来源于stack exchange,提问作者rayan daou
相关产品推荐
相关产品推荐

