为什么 <<- 赋值在我的函数中起作用,而 <- 却不起作用?
Why does <<- assignment work in my function, but <- doesn't?
我试图了解 <-
和 <<-
在实践中的区别。我在 R
中编写了以下函数,它依赖于我编写的其他几个小函数:
fun.exec <- function(x=dat){
id1 <- prompt1()
id2 <- prompt2()
el.type <- data.switch(di=id1)
dat.sifted <- data.sift(x, nc=id2)
plots.list <- evol.tiles(ds=dat.sifted, dt=el.type, nc=id2)
p <- evol.plot(l=plots.list, dt=el.type)
}
函数 prompt1
和 prompt2
从用户那里获取输入,el.type()
为数据分配字符串名称(用于自动描述不同的图),data.sift()
从大数据框对象中提取相关数据,evol.tiles()
生成各种 ggplots 以在网格中组织,然后 evol.plot()
将图放在网格中。
可以看出,data.sift()
和 evol.tiles()
函数都使用了 id2
用户的输入。当我按原样执行这个函数时,我得到一个错误:
Error in evol.tiles(ds = dat.sifted, dt = el.type, nc = id2) : object
'id2' not found
如果我将 id2 <- prompt2()
替换为 id2 <<- prompt2()
,代码将按预期运行。
我不明白的是为什么代码没有在 data.sift()
函数上中断,该函数也调用 id2
。我读了 help for assignments, a couple of related posts on Whosebug, and the Scope section from An Introduction to R 但我仍然不确定问题出在哪里。就好像在 data.sift()
中使用后,变量在环境中不再可用,我不明白是这样。
任何帮助将不胜感激。
更新:
这是提示代码:
prompt1 <- function(){
cat('What do you want to create plots for? Your options are:
1: data type A,
2: data type B,
3: data type C')
readline(prompt="Enter an integer: ")
}
prompt2 <- function(){
cat('How many nodes do you want to visualize?')
n <- readline(prompt="Enter an integer: ")
cat('\nProvide coordinates of each node to visualize separated by commas.')
l <- vector("list", n)
for (i in 1:n){
el <- readline(prompt=paste('Enter coordinnates for node',i,': '))
l[[i]] <- el
}
return(l)
}
对于 data.sift()
:
data.sift <- function(x, nc){
nl <- lapply(nc, function(l){as.integer(unlist(strsplit(l,",")))})
ds <- vector("list", length(nl))
for (i in 1:length(nl)){
ds[[i]] <- x[(x$x == nl[[i]][1] & x$y == nl[[i]][2] & x$z == nl[[i]][3]),]
}
return(ds)
}
和 evol.tiles()
:
evol.tiles <- function(ds, dt, nc){
require(ggplot2)
my.cols <- rainbow(length(ds))
my.names <- as.character(nc)
names(my.cols) <- my.names
my.list <- list()
for (i in 1:6){
for (ii in 1:length(id2)){
p <- ggplot(NULL, aes_(x = as.name(names(ds[[ii]][4]))))
p <- p + geom_line(data = ds[[ii]],
aes_(y = as.name(names(ds[[ii]][i])),
colour = as.character(nc[[ii]])))
}
p <- p + scale_colour_manual("Node",
breaks = as.character(nc),
values = my.cols)
my.list[[i-dr[1]+1]] <- p
}
return(my.list)
}
如评论中所述,我想我发现了问题 - 在处理一个最小的工作示例时,我发现在我的函数 evol.tiles()
中我调用了 id2
变量而不是 nc
(在内循环中)。我想当我将 <<-
用于 prompt2()
时,我被全局分配了它,然后当从 evol.tiles()
中调用时可以找到它,但是对于 <-
它不适用于 evol.tiles()
。
即便如此,我还是不太明白为什么会这样。我认为该函数应该在父环境中查找缺少的参数,并且由于 id2
是在 fun.exec()
中定义的,因此 time.evol()
应该能够找到正确的值。
这是一个简单的例子,展示了我期望代码的行为方式,即使变量命名不正确,就像我的情况一样:
test <- function(){x*x}
test()
Error in test() : object 'x' not found
如果我单独 运行 test()
函数,我会得到与我的函数相同的错误,这正是我所期望的。但是,如果我给 x
赋值,即
x <- 2
test()
[1] 4
该功能运行良好。有人能告诉我为什么我的函数不以同样的方式运行吗?
更新:
@Aaron:你给出的例子,即 rm(x); test2 <- function() { x <- 2; test() }; test2()
,对我来说执行得很好:
所以我还是不明白问题出在哪里。有什么想法吗?
我试图了解 <-
和 <<-
在实践中的区别。我在 R
中编写了以下函数,它依赖于我编写的其他几个小函数:
fun.exec <- function(x=dat){
id1 <- prompt1()
id2 <- prompt2()
el.type <- data.switch(di=id1)
dat.sifted <- data.sift(x, nc=id2)
plots.list <- evol.tiles(ds=dat.sifted, dt=el.type, nc=id2)
p <- evol.plot(l=plots.list, dt=el.type)
}
函数 prompt1
和 prompt2
从用户那里获取输入,el.type()
为数据分配字符串名称(用于自动描述不同的图),data.sift()
从大数据框对象中提取相关数据,evol.tiles()
生成各种 ggplots 以在网格中组织,然后 evol.plot()
将图放在网格中。
可以看出,data.sift()
和 evol.tiles()
函数都使用了 id2
用户的输入。当我按原样执行这个函数时,我得到一个错误:
Error in evol.tiles(ds = dat.sifted, dt = el.type, nc = id2) : object
'id2' not found
如果我将 id2 <- prompt2()
替换为 id2 <<- prompt2()
,代码将按预期运行。
我不明白的是为什么代码没有在 data.sift()
函数上中断,该函数也调用 id2
。我读了 help for assignments, a couple of related posts on Whosebug, and the Scope section from An Introduction to R 但我仍然不确定问题出在哪里。就好像在 data.sift()
中使用后,变量在环境中不再可用,我不明白是这样。
任何帮助将不胜感激。
更新: 这是提示代码:
prompt1 <- function(){
cat('What do you want to create plots for? Your options are:
1: data type A,
2: data type B,
3: data type C')
readline(prompt="Enter an integer: ")
}
prompt2 <- function(){
cat('How many nodes do you want to visualize?')
n <- readline(prompt="Enter an integer: ")
cat('\nProvide coordinates of each node to visualize separated by commas.')
l <- vector("list", n)
for (i in 1:n){
el <- readline(prompt=paste('Enter coordinnates for node',i,': '))
l[[i]] <- el
}
return(l)
}
对于 data.sift()
:
data.sift <- function(x, nc){
nl <- lapply(nc, function(l){as.integer(unlist(strsplit(l,",")))})
ds <- vector("list", length(nl))
for (i in 1:length(nl)){
ds[[i]] <- x[(x$x == nl[[i]][1] & x$y == nl[[i]][2] & x$z == nl[[i]][3]),]
}
return(ds)
}
和 evol.tiles()
:
evol.tiles <- function(ds, dt, nc){
require(ggplot2)
my.cols <- rainbow(length(ds))
my.names <- as.character(nc)
names(my.cols) <- my.names
my.list <- list()
for (i in 1:6){
for (ii in 1:length(id2)){
p <- ggplot(NULL, aes_(x = as.name(names(ds[[ii]][4]))))
p <- p + geom_line(data = ds[[ii]],
aes_(y = as.name(names(ds[[ii]][i])),
colour = as.character(nc[[ii]])))
}
p <- p + scale_colour_manual("Node",
breaks = as.character(nc),
values = my.cols)
my.list[[i-dr[1]+1]] <- p
}
return(my.list)
}
如评论中所述,我想我发现了问题 - 在处理一个最小的工作示例时,我发现在我的函数 evol.tiles()
中我调用了 id2
变量而不是 nc
(在内循环中)。我想当我将 <<-
用于 prompt2()
时,我被全局分配了它,然后当从 evol.tiles()
中调用时可以找到它,但是对于 <-
它不适用于 evol.tiles()
。
即便如此,我还是不太明白为什么会这样。我认为该函数应该在父环境中查找缺少的参数,并且由于 id2
是在 fun.exec()
中定义的,因此 time.evol()
应该能够找到正确的值。
这是一个简单的例子,展示了我期望代码的行为方式,即使变量命名不正确,就像我的情况一样:
test <- function(){x*x}
test()
Error in test() : object 'x' not found
如果我单独 运行 test()
函数,我会得到与我的函数相同的错误,这正是我所期望的。但是,如果我给 x
赋值,即
x <- 2
test()
[1] 4
该功能运行良好。有人能告诉我为什么我的函数不以同样的方式运行吗?
更新:
@Aaron:你给出的例子,即 rm(x); test2 <- function() { x <- 2; test() }; test2()
,对我来说执行得很好:
所以我还是不明白问题出在哪里。有什么想法吗?