我正在尝试在R包中动态生成引用类,并且它被证明相当困难。以下是我采取的方法和遇到的问题:
我正在创建一个包,我希望能够动态读取模式并自动生成关联的引用类(想想SOAP)。当然,这意味着我无法在包源中预先定义我的引用类。
我最初尝试使用简单的方法创建一个新类:
myClass <- setRefClass("NewClassName", fields=list(fieldA="character"))
当然,交互式执行时工作正常,但是当包含在包源中时,我收到locked binding
错误。从我的阅读中看,这看起来是因为当交互式运行时,类信息存储在未锁定的全局环境中,而我的包的基本环境被锁定。
然后我找到了一个建议使用某些东西的线程:
myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=globalenv())
当我尝试构建软件包时,这实际上已经崩溃了R / Studio,所以我没有记录它生成的错误,不幸的是,但它肯定没有用。
接下来我尝试在我的包中创建一个新环境,我可以使用它来存储这些引用类。所以我在我的包源中添加了一个.classEnv <- new.env()
行(不在任何函数内部),然后在创建新的引用类时尝试使用该类:
myClass <- setRefClass("NewClassName", fields=list(fieldA="character"), where=.classEnv)
这实际上似乎工作正常,但会产生以下警告:
> myClass <- setRefClass("NewClassName", where=.classEnv)
Warning message:
In getPackageName(where) :
Created a package name, ‘2013-04-23 10:19:14’, when none found
因此,由于某种原因,methods::getPackageName()
无法获取我的新环境所在的软件包?
有没有办法以不同的方式创建我的新环境,以便getPackageName()
可以正确识别包?我可以添加一些功能,让我帮助getPackageName()
检测包裹吗?如果我可以处理警告,或者我是否通过尝试动态创建它们来滥用引用类,这是否会起作用?
答案 0 :(得分:5)
为了进行对话,我发现getpackageName
将包名称存储在指定环境中的隐藏.packageName
变量中。
所以你可以用
来解决警告assign(".packageName", "MyPkg", envir=.classEnv)
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)
解决了警告,但是文档说不能无限期地信任.packageName
变量,我仍然觉得我正在攻击这个并且可能误解了关于引用类及其与环境的关系的重要事项。
文档中的完整详细信息:
软件包名称通常在加载软件包期间,通过INSTALL脚本或库函数安装。 (目前,该名称存储为对象.packageName,但未来不信任此。)
修改强>:
在进一步阅读之后,setPackageName
方法可能是更可靠的方法来设置环境的包名称。根据文档:
setPackageName
可用于在环境中建立包名称,否则该包名称将不具有包名称。这允许您在任意环境中创建类和/或方法,但通常最好通过标准R编程工具(package.skeleton等)创建包。
所以看起来有一个有效的解决方案如下:
setPackageName("MyPkg", .classEnv)
myClass <- setRefClass("NewClassName", fields=classFields, where=.classEnv)
这消除了警告信息,并且不依赖于任何记录为不稳定的信息。我还不清楚为什么有必要,但是......