为什么在全局工作区的函数中使用“<<-”有效,但在包中却无效?
Why does using "<<-" in a function in the global workspace work, but not in a package?
我正在使用 devtools 和 roxygen2(在 RStudio 中)创建一个包,但是在我构建包之后,我的功能不再按预期工作。然而,如果我在 RStudio 中加载函数的 .R 文件和 运行 函数,它会完美运行。我之前使用这种方法创建了另一个包并且它工作正常(13 个函数都按照我的其他包的预期工作),但我似乎无法让这个新的工作。
要开始创建包,我从以下开始:
library("devtools")
devtools::install_github("klutometis/roxygen")
library(roxygen2)
setwd("my parent directory")
create("triale")
到目前为止一切正常。因此,我将包含我的函数的 .R 文件放在 triale 文件夹下的 R 文件夹中。 .R 文件如下所示:
#' Trial Z Function
#'
#' This function counts the values in the columns
#' @param x is the number
#' @keywords x
#' @export
#' @examples
#' trialz()
trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
同样,如果我只是 运行 来自 .R 文件的代码,并测试它工作正常的功能。但要继续,接下来我输入:
setwd("./triale")
document()
更新了 triale 文档,加载了 triale,并编写了 NAMESPACE 和 trialz.Rd,以便 trialz.Rd 在 man 文件夹下,NAMESPACE 按预期在 triale 文件夹下。接下来我安装 triale:
setwd("..")
install("triale")
我知道这是有效的,因为我得到以下信息:
Installing triale
"C:/PROGRA~1/R/R-31~1.3/bin/x64/R" --vanilla CMD INSTALL \
"C:/Users/grice/Documents/R/triale" \
--library="C:/Users/grice/Documents/R/win-library/3.1" --install-tests
* installing *source* package 'triale' ...
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* DONE (triale)
Reloading installed triale
包现已构建,所以我执行以下操作:
library("triale")
library("data.table")
请注意,每当我加载包 data.table 时,我都会收到以下错误消息:
data.table 1.9.4 For help type: ?data.table
*** NB: by=.EACHI is now explicit. See README to restore previous behaviour.
不过好像不影响我的功能。所以现在是时候从我的包中测试我的功能了:
trialz(25)
这一切都过去了,我当然得到了一个填充的 df1 和 countit,但无论出于何种原因,视图总是空的(如 0 个变量的 0 个观测值)。
所以我使用下面的虚拟代码测试我的工作:
>trialy = function(x) {wid= c(25,x,25,25,25,1,1,1,1,1);
wc= c(rep("BYSTAR-1",10));
df2 <<- data.frame(wid, wc);
countitt <<- data.table(df2);
viewer <<- countitt[, .N, by = list(wid, wc)];
View(viewer)}
>trialy(25)
尽管这是完全相同的代码,只是更改了周围的名称,但它仍然有效。傻眼了,我打开 trialz.R 并从那里复制函数,然后 运行 如下所示,并且有效:
> trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
> trialz(25)
因为在我知道我的方法是可靠的之前我已经创建了一个包(那个包有 13 个不同的功能,所有这些功能都有效)。我只是不明白一个函数如何能像写的那样正常工作,但是当我打包它时,这个函数就不再起作用了。
同样,这里是使用我的包时它停止按预期工作的地方:
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
如果我的包有效,我的最终结果应该是这样的:
wid wc N
1 25 BYSTAR-1 5
2 1 BYSTAR-1 5
谁能解释为什么我打包函数后视图从未填充?我已经尽可能多地测试了它,我的结果对于任何愿意自己尝试的人来说应该是可重现的。
谢谢,感谢任何反馈。
我在编辑我的描述文件时忘记了一个重要的部分,因为我必须添加
Imports: data.table
NAMESPACE 文件也需要包含 data.table 包作为导入,如下所示:
import(data.table)
export(Z)
export(AS) .... etc.
这样做可确保无论何时您的包中的函数使用另一个包中的函数,都会在执行您的代码之前调用该(第二个)包。
您的问题是“<<-”不会在全局环境中而是在 parent 环境中创建变量。 (参见 help("<<-")
。)
函数的父环境是定义它的环境。在您直接在工作区中定义函数的情况下,该父环境实际上与您的工作区环境相同(即:.GlobalEnv
),这就是为什么您的变量会按照您期望的方式分配值。但是,在您的函数被打包的情况下,父环境是包环境,不是 .GlobalEnv
!这就是您在工作区中看不到变量被赋值的原因。
有关 R 环境的更多详细信息,请参阅 the chapter on environments in Hadley's book and How R Searches and Finds Stuff。
请注意,至少可以说,这样做不会被视为正确的调试技术。一般来说,您永远不会想要使用“<<-”运算符。
有关调试 R 代码的选项,请参阅 this question。我尤其喜欢 debugonce
函数。参见 ?debugonce
。
我正在使用 devtools 和 roxygen2(在 RStudio 中)创建一个包,但是在我构建包之后,我的功能不再按预期工作。然而,如果我在 RStudio 中加载函数的 .R 文件和 运行 函数,它会完美运行。我之前使用这种方法创建了另一个包并且它工作正常(13 个函数都按照我的其他包的预期工作),但我似乎无法让这个新的工作。
要开始创建包,我从以下开始:
library("devtools")
devtools::install_github("klutometis/roxygen")
library(roxygen2)
setwd("my parent directory")
create("triale")
到目前为止一切正常。因此,我将包含我的函数的 .R 文件放在 triale 文件夹下的 R 文件夹中。 .R 文件如下所示:
#' Trial Z Function
#'
#' This function counts the values in the columns
#' @param x is the number
#' @keywords x
#' @export
#' @examples
#' trialz()
trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
同样,如果我只是 运行 来自 .R 文件的代码,并测试它工作正常的功能。但要继续,接下来我输入:
setwd("./triale")
document()
更新了 triale 文档,加载了 triale,并编写了 NAMESPACE 和 trialz.Rd,以便 trialz.Rd 在 man 文件夹下,NAMESPACE 按预期在 triale 文件夹下。接下来我安装 triale:
setwd("..")
install("triale")
我知道这是有效的,因为我得到以下信息:
Installing triale
"C:/PROGRA~1/R/R-31~1.3/bin/x64/R" --vanilla CMD INSTALL \
"C:/Users/grice/Documents/R/triale" \
--library="C:/Users/grice/Documents/R/win-library/3.1" --install-tests
* installing *source* package 'triale' ...
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* DONE (triale)
Reloading installed triale
包现已构建,所以我执行以下操作:
library("triale")
library("data.table")
请注意,每当我加载包 data.table 时,我都会收到以下错误消息:
data.table 1.9.4 For help type: ?data.table
*** NB: by=.EACHI is now explicit. See README to restore previous behaviour.
不过好像不影响我的功能。所以现在是时候从我的包中测试我的功能了:
trialz(25)
这一切都过去了,我当然得到了一个填充的 df1 和 countit,但无论出于何种原因,视图总是空的(如 0 个变量的 0 个观测值)。
所以我使用下面的虚拟代码测试我的工作:
>trialy = function(x) {wid= c(25,x,25,25,25,1,1,1,1,1);
wc= c(rep("BYSTAR-1",10));
df2 <<- data.frame(wid, wc);
countitt <<- data.table(df2);
viewer <<- countitt[, .N, by = list(wid, wc)];
View(viewer)}
>trialy(25)
尽管这是完全相同的代码,只是更改了周围的名称,但它仍然有效。傻眼了,我打开 trialz.R 并从那里复制函数,然后 运行 如下所示,并且有效:
> trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
> trialz(25)
因为在我知道我的方法是可靠的之前我已经创建了一个包(那个包有 13 个不同的功能,所有这些功能都有效)。我只是不明白一个函数如何能像写的那样正常工作,但是当我打包它时,这个函数就不再起作用了。 同样,这里是使用我的包时它停止按预期工作的地方:
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
如果我的包有效,我的最终结果应该是这样的:
wid wc N
1 25 BYSTAR-1 5
2 1 BYSTAR-1 5
谁能解释为什么我打包函数后视图从未填充?我已经尽可能多地测试了它,我的结果对于任何愿意自己尝试的人来说应该是可重现的。 谢谢,感谢任何反馈。
我在编辑我的描述文件时忘记了一个重要的部分,因为我必须添加
Imports: data.table
NAMESPACE 文件也需要包含 data.table 包作为导入,如下所示:
import(data.table)
export(Z)
export(AS) .... etc.
这样做可确保无论何时您的包中的函数使用另一个包中的函数,都会在执行您的代码之前调用该(第二个)包。
您的问题是“<<-”不会在全局环境中而是在 parent 环境中创建变量。 (参见 help("<<-")
。)
函数的父环境是定义它的环境。在您直接在工作区中定义函数的情况下,该父环境实际上与您的工作区环境相同(即:.GlobalEnv
),这就是为什么您的变量会按照您期望的方式分配值。但是,在您的函数被打包的情况下,父环境是包环境,不是 .GlobalEnv
!这就是您在工作区中看不到变量被赋值的原因。
有关 R 环境的更多详细信息,请参阅 the chapter on environments in Hadley's book and How R Searches and Finds Stuff。
请注意,至少可以说,这样做不会被视为正确的调试技术。一般来说,您永远不会想要使用“<<-”运算符。
有关调试 R 代码的选项,请参阅 this question。我尤其喜欢 debugonce
函数。参见 ?debugonce
。