这个问题是这篇文章的后续问题,因为我仍然不完全相信,就代码的健壮性而言,养成打字namespace::foo()
习惯而不是仅仅打字foo()
并祈祷你得到想要的结果不会好得多; -)
实际问题
我知道这严重违反了“标准 R 约定”,但我只是说我很好奇 ;-)是否可以以某种方式将临时命名空间附加到搜索路径?
动机
在我的包mypkg
仍处于“开发阶段”的时候(即还不是真正的 R 包):
- 我想将我的功能导入环境
mypkg
而不是.GlobalEnv
- 然后附加
mypkg
到搜索路径(如果可能,作为真正的命名空间) - 为了能够打电话
mypkg::foo()
我完全意识到调用::
有其缺点(它比简单地输入函数名称并让 R 隐式处理查找需要更长的时间)和/或可能由于a) R 扫描搜索路径和b的方式而被认为是不必要的)包可以导入它们的依赖项(即使用“Imports”而不是“Depends”,不导出某些函数等)。但是由于某些包已经覆盖了某些(基本)功能,我已经看到我的代码至少崩溃了两次,所以我从“盲目信任”变成了“比抱歉更安全”模式; -)
我试过的
AFAIU,命名空间原则上只不过是某种特殊的环境
> search()
[1] ".GlobalEnv" "package:stats" "package:graphics"
[4] "package:grDevices" "package:utils" "package:datasets"
[7] "package:methods" "Autoloads" "package:base"
> asNamespace("base")
<environment: namespace:base>
还有attach()
将对象附加到搜索路径的功能。所以这就是我的想法:
temp.namespace <- new.env(parent=emptyenv())
attach(temp.namespace)
> asNamespace("temp.namespace")
Error in loadNamespace(name) :
there is no package called 'temp.namespace'
我想我必须以某种方式处理attachNamepace()
并弄清楚它在被调用之前会发生什么library()
。有任何想法吗?
编辑
关于 Hadley 的评论:我实际上不在乎附加的环境是成熟的命名空间还是只是一个普通的环境,只要我可以扩展::
同时保持“语法 sugering”功能(即能够调用pkg::foo()
而不是"::"(pkg="pkg", name="foo")()
) .
这是函数的"::"
样子:
> get("::")
function (pkg, name)
{
pkg <- as.character(substitute(pkg))
name <- as.character(substitute(name))
getExportedValue(pkg, name)
}
pkg
如果 R 检测到这实际上不是命名空间,而只是附加到搜索路径的一些环境,这也是它应该能够做的:
"::*" <- function (pkg, name)
{
pkg <- as.character(substitute(pkg))
name <- as.character(substitute(name))
paths <- search()
if (!pkg %in% paths) stop(paste("Invalid namespace environment:", pkg))
pos <- which(paths == pkg)
if (length(pos) > 1) stop(paste("Multiple attached envirs:", pkg))
get(x=name, pos=pos)
}
它有效,但没有语法糖:
> "::*"(pkg="tempspace", name="foo")
function(x, y) x + y
> "::*"(pkg="tempspace", name="foo")(x=1, y=2)
[1] 3
我将如何调用(忽略函数名称非常糟糕pkg::*foo(x=1, y=2)
的事实;-))?::*