为什么在全局工作区的函数中使用“<<-”有效,但在包中却无效?

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