Ответ 1
Проблема в конечном счете связана с поведением функции as.vector()
.
Когда вы применяете as.character()
к списку, он видит объект класса "list"
(не один из класса "Date"
). Поскольку для списков нет метода as.character()
, отправляется метод по умолчанию as.character.default
. Он выполняет следующие действия:
as.character.default
# function (x, ...)
# .Internal(as.vector(x, "character"))
# <bytecode: 0x0000000006793e88>
# <environment: namespace:base>
Как вы можете видеть, он сначала подготавливает объект данных, принуждая его к вектору. Выполнение as.vector()
непосредственно в списке объектов Date показывает, в свою очередь, что это то, что производит принуждение к целому, а затем к символу.
as.vector(list(Sys.Date()), "character")
# [1] "17567"
Как указывает Карл, объяснение выше, даже если оно точно, на самом деле не удовлетворяет. Более полный ответ требует просмотра того, что происходит под капотом, в коде C, выполняемом вызовом .Internal(as.vector(x, "character"))
. Весь соответствующий код C находится в исходном файле coerce.c.
Сначала do_asvector()
, который вызывает ascommon()
который вызывает coerceVector()
, который вызывает coerceVectorList()
и затем, наконец, coerceToString()
. coerceToString()
проверяет "typeof" обрабатываемый элемент, и в нашем случае, если это "REAL", переключается на этот блок кода:
case REALSXP:
PrintDefaults();
savedigits = R_print.digits; R_print.digits = DBL_DIG;/* MAX precision */
for (i = 0; i < n; i++) {
// if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
SET_STRING_ELT(ans, i, StringFromReal(REAL(v)[i], &warn));
}
R_print.digits = savedigits;
break;
И зачем он использует блок для объектов с типом REALSXP
? Потому что режим хранения объектов R Date
(как видно из выполнения mode(Sys.Date())
или typeof(Sys.Date())
).
Приёмник - это следующее: в цепочке событий, описанных выше, элементы списка не так или иначе пойманы и рассматриваются как объекты "Date"
, в то время как в области вызовов функций R и отправки метода. Вместо этого они передаются как "list"
(aka VECSXP
) в ряд функций C. И в этот момент это слишком поздно, поскольку функции C, которые обрабатывают этот список, ничего не знают о классе "Date"
его элементов. В частности, функция, которая в конечном счете выполняет преобразование в символ, coerceToCharacter()
видит только режим хранения элементов, который является REAL/numeric/double, и обрабатывает их, как если бы это было all, что они были,