Глобальные и локальные переменные в R

Я новичок в R, и я довольно запутался в использовании локальных и глобальных переменных в R.

Я прочитал несколько сообщений в Интернете, которые говорят, что если я использую = или <-, я назначу переменную в текущей среде, а с помощью <<- я могу получить доступ к глобальной переменной, когда внутри функции.

Однако, как я помню, в С++ локальные переменные возникают всякий раз, когда вы объявляете переменную внутри скобок {}, поэтому мне интересно, так ли это для R? Или это просто для функций из R, что мы имеем понятие локальных переменных.

Я сделал небольшой эксперимент, который, по-видимому, предполагает, что только скобок недостаточно, я получаю что-то неправильно?

{
   x=matrix(1:10,2,5)
}
print(x[2,2])
[1] 4

Ответ 1

Переменные, объявленные внутри функции, являются локальными для этой функции. Например:

foo <- function() {
    bar <- 1
}
foo()
bar

дает следующую ошибку: Error: object 'bar' not found.

Если вы хотите сделать bar глобальную переменную, вы должны сделать:

foo <- function() {
    bar <<- 1
}
foo()
bar

В этом случае bar доступен извне функции.

Однако, в отличие от C, С++ или многих других языков, скобки не определяют область переменных. Например, в следующем фрагменте кода:

if (x > 10) {
    y <- 0
}
else {
    y <- 1
}

y остается доступным после оператора if-else.

Как вы говорите, вы также можете создавать вложенные среды. Вы можете взглянуть на эти две ссылки, чтобы понять, как их использовать:

Здесь у вас есть небольшой пример:

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found

Ответ 2

<- выполняет назначение в текущей среде.

Когда вы находитесь внутри функции 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"

В первый раз, когда мы печатаем брусок, мы еще не назвали foo, но он все равно должен быть глобальным - это имеет смысл. Во второй раз мы печатаем его внутри foo перед вызовом baz, поэтому значение "в foo" имеет смысл. Ниже мы видим, что фактически делает <<-. Следующее значение, напечатанное "baz - before < -", даже если инструкция печати появляется после <<-. Это связано с тем, что <<- не выглядит в текущей среде (если вы не находитесь в глобальной среде, в этом случае <<- действует как <-). Таким образом, внутри baz значение bar остается как "в baz - до < < -". Как только мы вызываем baz, копия строки внутри foo изменяется на "в baz", но, как мы видим, глобальный bar не изменяется. Это связано с тем, что копия bar, которая определена внутри foo, находится в родительской среде, когда мы создали baz, так что это первая копия bar, которую видит <<- и, следовательно, копия, которую она присваивает, Таким образом, <<- не просто назначает глобальную среду.

<<- сложно, и я бы не рекомендовал его использовать, если вы можете его избежать. Если вы действительно хотите назначить глобальную среду, вы можете использовать функцию назначения и явно указать, что вы хотите назначить глобально.

Теперь я изменяю <<- на оператор присваивания, и мы можем видеть, какой эффект имеет:

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"

Итак, оба раза мы печатаем строку внутри foo, значение равно "в 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"