Добавление новых столбцов в ссылку на data.table внутри функции не всегда работает
При написании пакета, который опирается наdata.table
Я обнаружил странное поведение. У меня есть функция, которая удаляет и переупорядочивает некоторые столбцы по ссылке, и это работает просто отлично, то естьdata.table
Я прошел в был изменен без назначения выходной функции. У меня есть другая функция, которая добавляетновый колонки, но эти изменения не всегда сохраняются вdata.table
который был передан в.
Вот небольшой пример:
library(data.table) # I'm using 1.9.4
test <- data.table(id = letters[1:2], val=1:2)
foobar <- function(dt, col) {
dt[, (col) := 1]
invisible(dt)
}
test
# id val
#1: a 1
#2: b 2
saveRDS(test, "test.rds")
test2 <- readRDS("test.rds")
all.equal(test, test2)
#[1] TRUE
foobar(test, "new")
test
# id val new
#1: a 1 1
#2: b 2 1
foobar(test2, "new")
test2
# id val
#1: a 1
#2: b 2
Что случилось? Чем отличаетсяtest2
? Я могу изменить существующие столбцы на месте:
foobar(test, "val")
test
# id val new
#1: a 1 1
#2: b 1 1
foobar(test2, "val")
test2
# id val
#1: a 1
#2: b 1
Но добавляя кtest2
все еще не работает:
foobar(test2, "someothercol")
.Last.value
# id val someothercol
#1: a 1 1
#2: b 1 1
test2
# id val
#1: a 1
#2: b 1
Я не могу определить все случаи, когда я вижу это поведение, но сохранение и чтение из RDS - это первый случай, который я могу надежно воспроизвести. Запись и чтение из CSV, похоже, не имеют такой же проблемы.
Это проблема указателя аляЭта проблемаКак сериализация data.table уничтожает перераспределенные указатели? Есть ли простой способ их восстановить? Как я могу проверить их внутри своей функции, чтобы я мог восстановить указатели или ошибку, если операция не будет работать?
Я знаю, что могу назначить вывод функции как обходной путь, но это не оченьdata.table
-y. Разве это не создаст временную копию в памяти?
Арун проинструктировал, что это действительно проблема указателя, которая может быть диагностирована сtruelength
и фиксируется сsetDT
или жеalloc.col
, Я столкнулся с проблемой, заключающей в капсулу его решение в функции (продолжая приведенный выше код):
func <- function(dt) {if (!truelength(dt)) setDT(dt)}
func2 <- function(dt) {if (!truelength(dt)) alloc.col(dt)}
test2 <- readRDS("test.rds")
truelength(test2)
#[1] 0
truelength(func(test2))
#[1] 100
truelength(test2)
#[1] 0
truelength(func2(test2))
#[1] 100
truelength(test2)
#[1] 0
Таким образом, похоже, что локальная копия внутри функции корректно модифицируется, а эталонная версия - нет. Почему бы и нет?