Посмотрите на этот пример Plnkr
Переменная this
сильно отличается timesCalled
с каждым нажатием кнопки увеличивается только на 1. Ответ на мой личный вопрос:
.click( () => { } )
и
.click(function() { })
создают одинаковое количество функции при использовании в цикле, как вы можете видеть из подсчета Guid в Plnkr.
Определение R языка говорит об этом (в разделе 4.3.3 Оценка аргумента )
Семантика вызова функции в аргументе R - это вызов по значению. В общем случае предоставленные аргументы ведут себя так, как если бы они были локальными переменными, инициализированными поставляемым значением, и именем соответствующего формального аргумента. Изменение значения предоставленного аргумента внутри функции не повлияет на значение переменной в вызывающем кадре. [Выделение добавлено]
blockquote>Хотя это не описывает механизм, с помощью которого работает копирование в модификацию, он упоминает, что изменение объекта, переданного функции, не влияет на оригинал в вызывающий кадр.
Дополнительная информация, особенно в аспекте копирования на модификацию, приведена в описании
SEXP
s в руководстве R Internals , раздел 1.1 .2 Остальная часть заголовка . В частности, он указывает [Emphasis added]Поле
named
установлено и доступно макросамиSET_NAMED
иNAMED
и принимает значения0
,1
и2
. R имеет иллюзию 'по значению' , поэтому присваивание типаb <- a
появляется, чтобы сделать копию
a
и ссылаться на нее какb
. Однако , если ни впоследствииa
, ниb
не были изменены, нет необходимости копировать. Что действительно происходит, так это то, что новый символb
привязан к тому же значению, что иa
и полеnamed
объекта значения задано (в данном случае -2
). Когда объект будет изменен, полеnamed
будет проконсультироваться. Значение2
означает, что объект должен быть дублирован перед изменением. (Обратите внимание, что это не означает, что необходимо дублировать, только чтобы он дублировался независимо от того, нужно ли это или нет.) Значение0
означает, что известно, что никакие другиеSEXP
не делят данные с этим объектом, а поэтому его можно безопасно изменить. Значение1
используется для ситуаций, подобныхdim(a) <- c(7, 2)
, где в принципе две копии a существуют в течение времени вычисления как (в принципе)
a <- `dim<-`(a, c(7, 2))
но уже не так, и поэтому некоторые примитивные функции могут быть оптимизированы, чтобы избежать копирования в этом случае.
blockquote>Пока это не описывает ситуацию, когда объекты передаются в функции как аргументы, мы может вывести, что тот же самый процесс работает, особенно с учетом информации из определения языка R, приведенного ранее.
Обещания в оценке функций
Не думаю, что вполне правильно сказать, что обещание передано функции . Аргументы передаются функции, а используемые фактические выражения хранятся как обещания (плюс указатель на вызывающую среду). Только когда оценивается аргумент, это выражение, хранящееся в обещании, полученном и оцененном в среде, указанной указателем, процесс, известный как , принудительный .
Таким образом, t верю, что правильно говорить о pass-by-reference в этом отношении. R имеет семантику вызова по значению , но пытается избежать копирования, если значение, переданное аргументу, оценивается и изменяется.
Механизм NAMED является оптимизацией (как отмечено @ hadley в комментариях), который позволяет R отслеживать, нужно ли копировать при модификации. Есть некоторые тонкости, связанные с тем, как работает механизм NAMED, о котором говорил Питер Дальгаард (в потоке R Devel @mnel цитирует в своем комментарии к вопросу)
Я сделал несколько экспериментов над ним и обнаружил, что R всегда копирует объект под первой модификацией.
Вы можете увидеть результат на моей машине в http://rpubs.com/ wash978 / 5916
Пожалуйста, дайте мне знать, если я сделал какую-либо ошибку, спасибо.
Я выгружаю адрес памяти со следующим кодом C:
#define USE_RINTERNALS
#include <R.h>
#include <Rdefines.h>
SEXP dump_address(SEXP src) {
Rprintf("%16p %16p %d\n", &(src->u), INTEGER(src), INTEGER(src) - (int*)&(src->u));
return R_NilValue;
}
Он выведет 2 адреса:
SEXP
integer
Давайте скомпилируем и загрузим эту функцию C.
Rcpp:::SHLIB("dump_address.c")
dyn.load("dump_address.so")
Здесь sessionInfo
тестовой среды.
sessionInfo()
Сначала я проверяю свойство копии при записи , что R только копирует объект только при его изменении.
a <- 1L
b <- a
invisible(.Call("dump_address", a))
invisible(.Call("dump_address", b))
b <- b + 1
invisible(.Call("dump_address", b))
Объект b
копирует с a
при модификации. R реализует свойство copy on write
.
Затем я проверю, будет ли R копировать объект, когда мы модифицируем элемент вектора / матрицы.
a <- 1L
invisible(.Call("dump_address", a))
a <- 1L
invisible(.Call("dump_address", a))
a[1] <- 1L
invisible(.Call("dump_address", a))
a <- 2L
invisible(.Call("dump_address", a))
Адрес меняется каждый раз, что означает, что R не использует повторно память.
system.time(a <- rep(1L, 10^7))
invisible(.Call("dump_address", a))
system.time(a[1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
Для длинного вектора R повторно использовать память после первой модификации.
Кроме того, приведенный выше пример также показывает, что «изменение на месте» влияет на производительность, когда объект огромен.
system.time(a <- matrix(0L, 3162, 3162))
invisible(.Call("dump_address", a))
system.time(a[1,1] <- 0L)
invisible(.Call("dump_address", a))
system.time(a[1,1] <- 1L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
system.time(a[1] <- 2L)
invisible(.Call("dump_address", a))
Кажется, что R копирует объект только при первых модификациях.
Не знаю, почему.
system.time(a <- vector("integer", 10^2))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2)))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2)))
invisible(.Call("dump_address", a))
system.time(names(a) <- paste(1:(10^2) + 1))
invisible(.Call("dump_address", a))
Результат тот же. R только копирует объект при первой модификации.
NAMED
, также используемая с вызовами функций, с дополнительной проблемой обещаний? – Gavin Simpson 2 April 2013 в 14:17