2017-08-04 91 views
0

我有一個全局變量x,並且想要構建函數f,該函數在函數創建時返回值x。例如:在函數定義中使用全局變量的當前值

x <- 5 
f <- function() return(x) 
f() 
> 5 
x <- 10 
f() 
> 10 # Should return 5 

我想一個函數總是返回5(或任何的x值是在函數創建時),而不使用其他的全局變量。那可能嗎?

回答

2

單獨使用全局變量是不可能的。當函數被定義時,函數體中的變量都不會被實際評估,直到函數被調用。你想要的東西似乎是在創作時保持價值的封閉。而是寫一個函數返回一個函數

x <- 5 
getfun <- function() {z<-x; function() return(z)} 
f <- getfun() 
x<- 10 
g <- getfun() 
f() 
# [1] 5 
g() 
# [1] 10 

甚至更​​好,不要隱式地使用全局變量。創建一個函數,一組特定的參數,並返回一個新的功能

returnVal <- function(x) {force(x); function() return(x)} 
f<-returnVal(5) 
g<-returnVal(10) 
f() 
# [1] 5 
g() 
# [1] 10 
+0

用一行代碼:'f < - (function(){z <-x; function()return(z)})()'。 – nicola

+0

「變量不被評估,除非它們的值被實際請求」 - 這是錯誤的。承諾(包括函數參數)是唯一的。 –

+0

啊,的確如此。我誤解了。 –

2

1)這節省了X第一次F稱值,然後利用x的值,即使x已經被改變下一次f被調用。在本地環境中創建f並將f放置在該環境中。如果x以前不在那裏,現在就是。如果它以前在那裏,那麼它將被檢索並放回。結果是總會使用遇到的第一個x。

f <- local(function() { 
     p <- parent.env(environment()) 
     p$x <- x 
     x 
}) 


x <- 5 
f() 
## [1] 5 
x <- 10 
f() 
## [1] 5 

2)在評論@Konrad和@Frank建議以下變化中,我們根據f刪除分配,並把它在當地。

從功能的用戶角度來看,有一點不同。在函數定義時,這會實例化x的值,而(1)在第一次調用函數時實例化x,如果要分離定義和實例,這可能是一個優點。

x <- 5 
f <- local({ x <- x; function() x }) 
f() 
## [1] 5 
x <- 10 
f() 
## [1] 5 

3)我們也可以考慮完全分離從實例化的功能。這也可以通過再次調用e $ init()來隨時重新初始化。

e <- local({ 
     init <- function() { 
      p <- parent.env(environment()) 
      p$x <- x 
     } 
     run = function() x 
     environment() 
    }) 

x <- 5 
e$init() 
e$run() 
## [1] 5 

x <- 10 
e$run() 
## [1] 5 

4)(3)可以使用各種面向對象的框架,如引用類,原或R 6中來實現。在原這將是這樣的:

library(proto) 

p <- proto(init = function(.) .$x <- x, run = function(.) x) 

x <- 5 
p$init() 
p$run() 
## [1] 5 

x <- 10 
p$run() 
## [1] 5 
+1

不需要'parent.env' - 'x < - x'可以很好地工作(雖然看起來很奇怪)。 –

+0

我們需要將x注入到父環境中,而不僅僅是檢索它。 x < - x不會那樣做。 –

+1

我已經完成了'f < - local({x = 5; function()x})'',這似乎工作。 – Frank

3

還是用body另一種選擇:

f<-`body<-`(function() {},value=x) 

實施例:

x<-10 
f<-`body<-`(function() {},value=x) 
f() 
#[1] 10 
x<-100 
f() 
#[1] 10 

挖的body的源代碼,這裏是一個更好的解決方法相當於上面使用的as.function

f<-as.function(list(x))