R语言中如何基于预定义列表或通过循环为S4类槽位赋值?
R语言中如何基于预定义列表或通过循环为S4类槽位赋值?
我来帮你搞定这个S4类槽位批量赋值的问题~先拆解下你之前遇到的坑,再给你几个靠谱的解决方案:
先说说你之前两种方案出错的原因
关于Option A的错误
你在创建prototype的时候,setNames(as.list(myVals), as.list(mySlots))这里的名字参数用了列表类型,但setNames的第二个参数要求是字符向量,不是列表。你用as.list(mySlots)得到的是list("myA", "c"),这会导致prototype的名字识别异常,进而触发类型不匹配的错误。另外,你的初始值类型是对的,这点没问题。
关于Option B的initialize方法问题
你用字符串拼接的方式尝试赋值,这种方法根本不会真正修改.Object对象。do.call("<-", ...)是在函数的局部环境里创建一个变量,而不是修改传入的S4对象。正确的做法是用R专门提供的slot()函数来操作槽位。
正确的解决方案
方案一:用prototype正确初始化类
先修正mySlotValues的创建方式,确保名字是字符向量,再创建带初始值的类:
# 定义槽位相关参数 mySlots <- c("myA", "c") myTypes <- c("numeric", "character") myVals <- c(1222, "blabla") # 构建槽位类型列表(这部分你之前的代码是对的) mySlotTypes <- setNames(as.list(myTypes), mySlots) # 构建槽位初始值列表:名字用字符向量,而非列表 mySlotValues <- setNames(as.list(myVals), mySlots) # 创建带prototype的S4类 setClass("B1", do.call("representation", mySlotTypes), prototype = do.call("prototype", mySlotValues) ) # 测试创建对象 x <- new("B1") str(x)
运行后会看到槽位已经被正确初始化:
Formal class 'B1' [package ".GlobalEnv"] with 2 slots ..@ myA: num 1222 ..@ c : chr "blabla"
方案二:编写正确的initialize方法
如果需要更灵活的初始化逻辑(比如根据参数动态赋值),可以用slot()函数在initialize方法里循环赋值:
# 先重新定义不带prototype的类 setClass("B1", do.call("representation", mySlotTypes) ) # 编写initialize方法 setMethod("initialize", signature = "B1", definition = function(.Object, ...) { # 遍历所有槽位名称,逐个赋值 for(i in slotNames(.Object)) { slot(.Object, i) <- mySlotValues[[i]] } # 调用父类的initialize方法,兼容默认行为 .Object <- callNextMethod(.Object, ...) return(.Object) }) # 测试 x <- new("B1") str(x)
方案三:创建对象后批量赋值
如果不想修改类定义,也可以在创建空对象后,用循环批量给槽位赋值:
# 创建空的B1对象 x <- new("B1") # 循环遍历初始值列表,给每个槽位赋值 for(i in names(mySlotValues)) { slot(x, i) <- mySlotValues[[i]] } str(x)
总结
- 用
prototype初始化是最简洁的方式,注意名字参数必须是字符向量; - 编写
initialize方法时,一定要用slot()函数操作对象,别用字符串拼接的赋值方式; - 后期批量修改槽位,用循环+
slot()的方式简单直接。
备注:内容来源于stack exchange,提问作者teddyCyen
相关产品推荐
相关产品推荐

