正如弗兰克所指出的,问题在于(有些不可见)有几种不同类型的NA. NA在命令行键入时产生的一个是 class "logical",但也有NA_integer_, NA_real_,NA_character_和NA_complex_.
在您的第一个示例中,初始data.table将 column 的类设置b为“字符”,然后NA将第二个示例中的 thedata.table强制设置为NA_character_. 但是,在第二个示例中,NA第一个data.table将 columnb的类设置为“逻辑”,并且当第二个 data.table 中的同一列被强制为“逻辑”时,它被转换为逻辑 NA。(试着as.logical("x")看看为什么。)
这一切都相当复杂(至少要表达清楚),但有一个相当简单的解决方案。只需创建一个 1 行模板data.table,并将其添加到data.table您想要的每个列表中rbind()。它将每列的类建立为您想要的,无论data.table传递给的列表中跟随它的是什么rbind(),并且一旦其他所有内容绑定在一起就可以修剪掉。
library(data.table)
## The two lists of data.tables from the OP
A <- list(data.table(x=1, b='x'),data.table(x=1, b=NA))
B <- list(data.table(x=1, b=NA),data.table(x=1, b='x'))
## A 1-row template, used to set the column types (and then removed)
DT <- data.table(x=numeric(1), b=character(1))
## Test it out
do.call(rbind, c(list(DT), A))[-1,]
# x b
# 1: 1 x
# 2: 1 NA
do.call(rbind, c(list(DT), B))[-1,]
# x b
# 1: 1 NA
# 2: 1 x
## Finally, as _also_ noted by Frank, rbindlist will likely be more efficient
rbindlist(c(list(DT), B)[-1,]