作者:johnylulu2502904467 | 来源:互联网 | 2022-12-02 17:26
1> Josh O'Brien..:
您的两个第一个示例因不同原因而失败.要了解这两个失败,首先要了解一下knitr和rmarkdown如何评估代码块.
knitr的通用代码块评估程序
当您调用rmarkdown::render()
文件时,每个代码块最终都会通过调用来评估evaluate::evaluate()
.就其评估行为和范围规则而言,其evaluate()
行为几乎与基本R函数完全相同eval()
.
(evaluate::evaluate()
最大的不同之处在于eval()
它如何处理每个计算表达式的输出.如上所述?evaluate
,除了评估作为第一个参数传递的表达式之外,它还"捕获重新创建输出所需的所有信息,就像复制了一样并将代码粘贴到R终端".该信息包括图表和警告以及错误消息,这就是为什么它在像knitr这样的包中非常方便!)
在任何情况下,evaluate()
函数内的最终调用knitr:::block_exec()
看起来都是这样的
evaluate::evaluate(code, envir = env, ...)
其中:
code
是一个字符串向量,给出构成当前块的(可能是多个)表达式.
env
是您envir
在原始调用中提供正式参数的值rmarkdown::render()
.
你的第一个例子
在您的第一个示例中,envir
是列表,而不是环境.在这种情况下,评估是在函数调用创建的本地环境中执行的.未解决的符号(如记录在这两个?eval
和?evaluate
)的寻找列表中的第一个传递envir
的环境链,然后与由给定的开始enclos
参数.至关重要的是,分配是临时评估环境的本地分配,一旦函数调用完成,它就不存在了.
因为evaluate()
在表达式的字符向量上一次一个地操作,所以当envir
列表时,在其中一个表达式中创建的变量将不可用于后续表达式.
当envir
参数to rmarkdown::render()
是一个列表时,你的代码块最终会被这样的调用评估:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- list(y = 1:10)
evaluate(code, envir = env)
## Or, for prettier printing:
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## > print(x)
## Error in print(x): object 'x' not found
效果与使用以下内容完全相同eval()
:
env <- list(y =1 :10)
eval(quote(x <- "don't you ignore me"), envir = env)
eval(quote(x), envir = env)
## Error in eval(quote(x), envir = env) : object 'x' not found
你的第二个例子
何时envir=
返回环境as.environment(list())
,您会因其他原因而出错.在这种情况下,您的代码块最终会通过以下调用进行评估:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- as.environment(list(y = 1:10))
evaluate(code, envir = env)
## Or, for prettier printing:
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## Error in x <- "don't you ignore me!": could not find function "<-"
## > print(x)
## Error in print(x): could not find function "print"
正如您所指出的那样,这会失败,因为as.environment()
返回一个环境,其封闭环境是空的环境(即返回的环境emptyenv()
).evaluate()
(就像eval()
那样)寻找符号<-
,env
并且当它在那里找不到它时,启动封闭环境链,这里不包含任何匹配.(回想一下,当envir
环境而不是列表时,enclos
不使用该参数.)
推荐解决方案
要做你想做的事,你需要创建一个环境:(1)包含你列表中的所有对象; (2)具有作为其封闭环境的呼叫的父环境render()
(即render()
通常评估呼叫的环境).最简洁的方法是使用漂亮的list2env()
函数,如下所示:
env <- list2env(list(y="hello"), parent.frame())
render('test.Rmd', output_format = "html_document",
output_file = 'test.html',
envir = env)
这样做会导致您的代码块被代码评估,如下所示,这是您想要的:
library(evaluate)
code <- c('x <- "don\'t you ignore me!"',
'print(x)')
env <- list2env(list(y = 1:10), envir = parent.frame())
evaluate(code, envir = env)
replay(evaluate(code, envir = env))
## > x <- "don't you ignore me!"
## > print(x)
## [1] "don't you ignore me!"