您遇到问题的原因是您将对象传递到函数的本地命名空间中。这是关于 R 的伟大/可怕的事情之一:它允许隐式变量声明,然后随着命名空间变得更深而实现取代。
这会影响您,因为函数会在当前命名空间中创建一个新命名空间。我假设对象“myTable”最初是在全局命名空间中创建的,但是当它被传递到函数“title.asterisk”时,一个新的函数本地命名空间现在具有一个具有相同属性的对象。这样做是这样的:
title.asterisk <- function(myTable){ do some stuff to 'myTable' }
在这种情况下,函数“title.asterisk”不会对全局对象“myTable”进行任何更改。相反,会创建一个同名的本地对象,因此本地对象会取代全局对象。如果我们以这种方式调用函数title.asterisk(myTable),函数只对局部变量进行更改。
修改全局对象有两种直接方式(也有很多间接方式)。
选项 1:正如您提到的,第一个是让函数返回对象并覆盖全局对象,如下所示:
title.asterisk <- function(myTable){
do some stuff to 'myTable'
return(myTable)
}
myTable <- title.asterisk(myTable)
这没关系,但您的代码仍然有点难以理解,因为实际上有两个不同的“myTable”对象,一个是全局对象,一个是函数本地对象。许多编码人员通过添加句点“。”来澄清这一点。在变量参数前面,像这样:
title.asterisk <- function(.myTable){
do some stuff to '.myTable'
return(.myTable)
}
myTable <- title.asterisk(myTable)
好的,现在我们有一个视觉提示,这两个变量是不同的。这很好,因为我们不想在以后尝试调试代码时依赖于不可见的东西,例如命名空间取代。它只会让事情变得比他们必须的更难。
选项 2:您可以只在函数内修改对象。当您想要对对象进行破坏性编辑并且不希望内存膨胀时,这是更好的选择。如果您正在进行破坏性编辑,则无需保存原始副本。此外,如果您的对象足够大,您不想在不需要时复制它。要对全局命名空间对象进行编辑,只需不要将其传递给函数或从函数中声明它。
title.asterisk <- function(){ do some stuff to 'myTable' }
现在我们正在函数内直接编辑对象“myTable”。我们没有传递对象的事实使我们的函数寻找更高级别的命名空间来尝试解析变量名。瞧,它发现了一个更高的“myTable”对象!函数中的代码对对象进行更改。
注意事项:我讨厌调试。我的意思是我真的很讨厌调试。这在 R 中对我来说意味着一些事情:
- 我将几乎所有内容都包装在一个函数中。当我编写代码时,一旦我得到一个工作,我将它包装在一个函数中并将它放在一边。我大量使用'.'为我所有的函数参数添加前缀,并且对于它所在的命名空间的本地内容不使用任何前缀。
- 我尽量不在函数内修改全局对象。我不喜欢这会导致什么。如果需要修改一个对象,我会在声明它的函数中对其进行修改。这通常意味着我有多层函数调用函数,但这使我的工作既模块化又易于理解。
- 我注释了我的所有代码,解释了每一行或每一块的用途。这似乎有点无关,但我发现这三件事对我来说是一起的。一旦你开始在函数中包装编码,你会发现自己想要重用更多的旧代码。这就是好的评论的用武之地。对我来说,这是一个必要的部分。