<-
выполняет присваивание в текущей среде.
Когда вы находитесь внутри функции, R создает для вас новую среду. По умолчанию он включает все из среды, в которой он был создан, поэтому вы также можете использовать эти переменные, но все новое, что вы создаете, не будет записано в глобальную среду.
В большинстве случаев <<-
будет присваиваться переменным уже в глобальной среде или создавать переменную в глобальной среде, даже если вы находитесь внутри функции. Однако это не так просто. Что он делает, так это проверяет родительскую среду на наличие переменной с интересующим именем. Если он не находит его в родительской среде, он переходит к родительскому элементу родительской среды (на момент создания функции) и ищет там. Он продолжает движение вверх в глобальную среду и, если он не найден в глобальной среде, присваивает переменную в глобальной среде.
Это может проиллюстрировать, что происходит.
bar <- "global"
foo <- function(){
bar <- "in foo"
baz <- function(){
bar <- "in baz - before <<-"
bar <<- "in baz - after <<-"
print(bar)
}
print(bar)
baz()
print(bar)
}
> bar
[1] "global"
> foo()
[1] "in foo"
[1] "in baz - before <<-"
[1] "in baz - after <<-"
> bar
[1] "global"
В первый раз, когда мы печатаем bar, мы еще не вызвали foo
его, поэтому он все равно должен быть глобальным - это имеет смысл. Во второй раз мы печатаем его внутри foo
перед вызовом, baz
поэтому значение in foo имеет смысл. Ниже мы видим, что <<-
происходит на самом деле. Следующим напечатанным значением будет «in baz - before << -», хотя оператор печати идет после <<-
. Это потому, <<-
что не смотрит в текущую среду (если вы не находитесь в глобальной среде, и в этом случае <<-
действует как <-
). Таким образом, внутри baz
значение бара остается как «in baz - before << -». Как только мы вызываем baz
копию бара внутри, меняем foo
на «in baz», но, как мы видим, глобальное значение bar
не меняется.bar
который определен внутри, foo
находится в родительской среде, когда мы создавали, baz
поэтому это первая копия, bar
которую <<-
видит, и, следовательно, копия, которой она назначается. Так что <<-
это не просто прямое присвоение глобальной среде.
<<-
сложно, и я бы не рекомендовал его использовать, если вы можете этого избежать. Если вы действительно хотите назначить глобальную среду, вы можете использовать функцию назначения и явно указать ей, что вы хотите назначить глобально.
Теперь я меняю <<-
оператор на оператор assign, и мы можем увидеть, какой эффект это имеет:
bar <- "global"
foo <- function(){
bar <- "in foo"
baz <- function(){
assign("bar", "in baz", envir = .GlobalEnv)
}
print(bar)
baz()
print(bar)
}
bar
#[1] "global"
foo()
#[1] "in foo"
#[1] "in foo"
bar
#[1] "in baz"
Итак, оба раза мы печатаем bar внутри foo
значения «in foo» даже после вызова baz
. Это потому, что мы assign
даже не рассматривали копию bar
внутри foo, потому что мы сказали, где именно искать. Однако на этот раз значение bar в глобальной среде было изменено, потому что мы явно присвоили ему значение.
Теперь вы также спросили о создании локальных переменных, и вы можете сделать это довольно легко, не создавая функцию ... Нам просто нужно использовать local
функцию.
bar <- "global"
# local will create a new environment for us to play in
local({
bar <- "local"
print(bar)
})
#[1] "local"
bar
#[1] "global"
globalenv(); globalenv() %>% parent.env; globalenv() %>% parent.env %>% parent.env
,…