Почему моя функция R обладает знанием переменных, которые не указаны в качестве аргументов? [Дубликат]

Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «таинствами» JavaScript.

Давайте начнем с простой функции JavaScript:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

Это простой синхронный вызов функции (где каждая строка кода выполняется одна за другой в последовательность), и результат будет таким же, как ожидалось.

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

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, на самом деле это довольно логично, если вы посмотрите на код. функция foo() после выполнения ничего не возвращает (таким образом, возвращаемое значение равно undefined), но оно запускает таймер, который выполняет функцию после 1s, чтобы вернуть «wohoo». Но, как вы можете видеть, значение, присвоенное бару, является немедленно возвращенным материалом из foo (), а не что-либо еще, что приходит позже.

Итак, как мы решаем эту проблему?

Давайте попросим нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что это означает: это означает, что функция гарантирует, что вы предоставите любой результат, который он получит в будущем. поэтому давайте посмотрим на это в нашей маленькой проблеме выше:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when exececution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

Таким образом, резюме - для решения асинхронных функций, таких как вызовы на основе ajax и т. д., вы можете использовать обещание resolve значение (которое вы намерены вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.

9
задан Jonas 10 March 2015 в 19:04
поделиться

4 ответа

Вы можете проверить, отображается ли имя переменной в списке глобальных переменных. Обратите внимание, что это несовершенно, если глобальная переменная, о которой идет речь, имеет то же имя, что и аргумент вашей функции.

if (deparse(substitute(var)) %in% ls(envir=.GlobalEnv))
    stop("Do not use a global variable!")

Функция stop() остановит выполнение функции и отобразит данное сообщение об ошибке.

6
ответ дан Alex A. 25 August 2018 в 22:17
поделиться

Другой способ (или стиль) - сохранить все глобальные переменные в специальной среде:

with( globals <- new.env(), {
  # here define all "global variables"  
  sUm <- 10
  mEan <- 5
})

# or add a variable by using $
globals$another_one <- 42

Тогда функция не сможет их получить:

sum <- function(x,y){
  sum = x+y
  return(sUm)
}

sum(1,2)
# Error in sum(1, 2) : object 'sUm' not found

Но вы всегда можете использовать их с глобалями $:

globals$sUm
[1] 10

Чтобы управлять дисциплиной, вы можете проверить, есть ли какая-либо глобальная переменная (кроме функций) вне globals:

setdiff(ls(), union(lsf.str(), "globals")))
2
ответ дан bergant 25 August 2018 в 22:17
поделиться

Использование get является способом:

sUm <- 10
sum <- function(x,y){
  sum <- x+y
  #with inherits = FALSE below the variable is only searched 
  #in the specified environment in the envir argument below
  get('sUm', envir = environment(), inherits=FALSE) 
}

Выход:

> sum(1,6)
Error in get("sUm", envir = environment(), inherits = FALSE) : 
  object 'sUm' not found

Наличие правого sum в функции get все равно будет только смотреть внутри функции окружение для переменной, что означает, что если бы существовали две переменные: одна внутри функции и одна в глобальной среде с тем же именем, функция всегда будет искать переменную внутри среды функции и никогда не будет в глобальной среде:

sum <- 10
sum2 <- function(x,y){
  sum <- x+y
  get('sum', envir = environment(), inherits=FALSE) 
}

> sum2(1,7)
[1] 8
3
ответ дан LyzandeR 25 August 2018 в 22:17
поделиться

Невозможно постоянно изменять, как изменяются переменные, потому что это нарушит множество функций. Поведение, которое вам не нравится, на самом деле очень полезно во многих случаях.

Если переменная не найдена в функции, R проверяет среду, в которой функция была определена для такой переменной. Вы можете изменить эту среду с помощью функции environment(). Например

environment(sum) <- baseenv()
sum(4,5)
# Error in sum(4, 5) : object 'sUm' not found

Это работает, потому что baseenv() указывает на «базовую» среду, которая пуста. Однако обратите внимание, что у вас нет доступа к другим функциям с помощью этого метода

myfun<-function(x,y) {x+y}
sum <- function(x,y){sum = myfun(x+y); return(sUm)}

environment(sum)<-baseenv()
sum(4,5)
# Error in sum(4, 5) : could not find function "myfun"

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

Вы должны вручную изменить среду для каждой функции, которую вы пишете. Опять же, нет способа изменить это поведение по умолчанию, потому что многие из базовых функций и функций R, определенных в пакетах, полагаются на это поведение.

5
ответ дан MrFlick 25 August 2018 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: