R中data.table的colnames()函数引用传递行为是否正常?
这个行为完全正常,我来给你解释清楚
你遇到的情况是data.table的引用语义和R对象赋值特性共同导致的,完全符合预期,不是bug。
背后的原因
当你执行column_names = colnames(DT)时,并没有生成一个独立的列名字符向量副本——column_names实际上是指向DT对象内部存储列名的内存位置的"引用"。
而data.table的一大设计特点是原地修改(in-place modification):当你用DT[, e := 23:28]新增列时,它会直接修改原DT对象的结构(包括列名),而不是创建一个新的data.table。因为column_names和DT的列名指向同一块内存,所以column_names的内容会跟着更新。
如何保留原列名的独立副本?
如果你想让column_names不受后续DT修改的影响,需要显式用copy()函数创建一个独立的向量:
library(data.table) DT = data.table( ID = c("b","b","b","a","a","c"), a = 1:6, b = 7:12, c = 13:18 ) # 用copy()生成独立的列名副本 column_names = copy(colnames(DT)) DT[, e := 23:28] column_names # 此时输出的是原列名:"ID" "a" "b" "c",不会包含"e"
简单验证
你可以用tracemem()工具直观看到引用关系:
DT = data.table( ID = c("b","b","b","a","a","c"), a = 1:6, b = 7:12, c = 13:18 ) # 未用copy的情况 cn_ref = colnames(DT) tracemem(cn_ref) # 输出内存地址A DT[, e := 23:28] tracemem(cn_ref) # 地址还是A,但内容已经变成包含"e"的列名 # 用copy的情况 cn_copy = copy(colnames(DT)) tracemem(cn_copy) # 输出不同的内存地址B DT[, f := 29:34] cn_copy # 仍然是包含"ID""a""b""c""e"的列名,不会新增"f"
内容的提问来源于stack exchange,提问作者Alfstat
相关产品推荐
相关产品推荐

