是否在函数中显式调用return
不久前,R核心团队的Simon Urbanek(我相信)推荐用户在函数结束时显式调用是否在函数中显式调用return,r,R,不久前,R核心团队的Simon Urbanek(我相信)推荐用户在函数结束时显式调用return(他的评论被删除): 相反,他建议: foo = function() { value } 可能在这种情况下,需要: foo = function() { if(a) { return(a) } else { return(b) } } 他的评论揭示了为什么不调用return,除非严格需要是件好事,但这被删除了 我的问题是:为什么调用return不更快或更好,因此更可取?似乎
return
(他的评论被删除):
相反,他建议:
foo = function() {
value
}
可能在这种情况下,需要:
foo = function() {
if(a) {
return(a)
} else {
return(b)
}
}
他的评论揭示了为什么不调用return
,除非严格需要是件好事,但这被删除了
我的问题是:为什么调用
return
不更快或更好,因此更可取?似乎没有return()
会更快
library(rbenchmark)
x <- 1
foo <- function(value) {
return(value)
}
fuu <- function(value) {
value
}
benchmark(foo(x),fuu(x),replications=1e7)
test replications elapsed relative user.self sys.self user.child sys.child
1 foo(x) 10000000 51.36 1.185322 51.11 0.11 0 0
2 fuu(x) 10000000 43.33 1.000000 42.97 0.05 0 0
库(rbenchmark)
问题是:为什么不(明确地)调用return更快或更好,因而更可取?
R文档中没有做出这种假设的陈述。
主页“函数”显示:
function( arglist ) expr
return(value)
不打电话返回是否更快?
function()
和return()
都是基本函数,function()
本身即使不包含return()
函数也会返回上一次计算的值
if(a) {
return(a)
} else {
return(b)
}
用最后一个值作为参数调用return()
作为基本体('return')
将完成相同的工作,但需要再调用一次。因此,这个(通常)不必要的.Primitive('return')
调用可以提取额外的资源。
然而,简单的测量表明,产生的差异非常小,因此不能成为不使用显式返回的原因。以下绘图是根据以这种方式选择的数据创建的:
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x) vector(length=x,mode="numeric"))(x)
,repeats)) }
bench_ret2 <- function(x,repeats) { system.time(rep(
# with explicit return
(function(x) return(vector(length=x,mode="numeric")))(x)
,repeats)) }
maxlen <- 1000
reps <- 10000
along <- seq(from=1,to=maxlen,by=5)
ret <- sapply(along,FUN=bench_ret2,repeats=reps)
nor <- sapply(along,FUN=bench_nor2,repeats=reps)
res <- data.frame(N=along,ELAPSED_RET=ret["elapsed",],ELAPSED_NOR=nor["elapsed",])
# res object is then visualized
# R version 2.15
这取决于程序员的策略和编程风格他使用什么风格,他可以使用no return(),因为这不是必需的
R核心程序员使用这两种方法,即使用和不使用显式return(),因为可以在“base”函数源中找到
很多情况下,只使用return()(无参数)在情况下返回NULL以辅助停止函数
if(a) {
return(a)
} else {
return(b)
}
由于标准用户或使用R的分析师看不到真正的区别,因此不清楚它是否更好
我的观点是,问题应该是:使用来自R实现的显式返回是否有任何危险
或者,也许更好,编写函数代码的用户应该总是问:在函数代码中使用显式返回(或将要返回的对象作为代码分支的最后一页)而不是使用显式返回有什么影响?如果每个人都同意
return
在函数体的末尾不是必需的
不使用return
稍微快一点(根据@Alan的测试,4.3微秒比5.1微秒)
我们是否应该在函数结束时停止使用return
?我当然不会,我想解释一下原因。我希望听到其他人是否同意我的观点。如果这不是对OP的直截了当的回答,而更像是一个冗长的主观评论,我道歉
我不使用return
的主要问题是,正如Paul指出的,函数体中还有其他地方可能需要它。如果你被迫在函数的中间使用<代码>返回<代码>某个地方,为什么不让所有的代码>返回< /COD>语句显式?我讨厌前后矛盾。而且我认为代码读起来更好;可以扫描函数,轻松查看所有退出点和值
保罗举了这个例子:
foo = function() {
if(a) {
return(a)
} else {
return(b)
}
}
不幸的是,有人可能会指出,它可以很容易地改写为:
foo = function() {
if(a) {
output <- a
} else {
output <- b
}
output
}
foo=function(){
如果(a){
输出这是一个有趣的讨论。我认为@flodel的例子非常好。但是,我认为它说明了我的观点(并且@koshke在评论中提到了这一点),即return
在使用命令式而不是函数式编码风格时是有意义的
我不是要详细说明这一点,但我会像这样重写foo
:
foo = function() ifelse(a,a,b)
e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
do_stuff
ifelse(c,1,sapply(seq(b),d_func))
}
bar <- function () {
do_stuff
sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}
f = function (a, b) {
if (precondition(a)) calculation(b)
}
函数样式避免状态更改,例如存储输出的值。在这种样式中,返回是不合适的;foo
看起来更像一个数学函数
if(a) {
return(a)
} else {
return(b)
}
我同意@flodel的观点:在bar
中使用一个复杂的布尔变量系统将变得不那么清晰,当你有return
时,它将变得毫无意义。bar
语句之所以如此易于return
语句,是因为它是以命令式编写的。实际上,布尔变量代表“状态”功能性风格中避免的变化
用函数式重写bar
确实很困难,因为它只是伪代码,但其思想是这样的:
foo = function() ifelse(a,a,b)
e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
do_stuff
ifelse(c,1,sapply(seq(b),d_func))
}
bar <- function () {
do_stuff
sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}
f = function (a, b) {
if (precondition(a)) calculation(b)
}
在函数式中,返回的值自然地落在函数的末尾。同样,它看起来更像一个数学函数
if(a) {
return(a)
} else {
return(b)
}
< GSee >在<代码>中勾勒出的警告,IFE/<代码>肯定是有趣的,但我不认为他们是在劝阻函数的使用。事实上,<代码> IFOR/<代码>具有自动矢量化功能的优点。例如,考虑一个稍微修改的版本<代码> FoO >:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
当length(a)
为1时,此函数可以正常工作。但是如果使用ifelse
foo = function (a) ifelse(a,a,b)
现在foo
可以在a
的任何长度上工作。事实上,当a
是一个矩阵时,它甚至可以工作。返回与test
形状相同的值是一个有助于矢量化的功能,而不是一个问题。如果在末尾添加额外的语句,则不在末尾显式地添加“return”e方法结束时,突然返回值错误:
foo <- function() {
dosomething()
}
我们希望我们的代码返回dosomething()
的值,但它不再返回
通过显式返回,这一点变得非常明显:
foo <- function() {
return( dosomething() )
dosomething2()
}
foo我认为return
是一种技巧。一般来说,函数中最后一个表达式的值会变成函数的值
ugly <- function(species, x, y){
if(length(species)>1) stop("First argument is too long.")
if(species=="Mickey Mouse") return("You're kidding!")
### do some calculations
if(grepl("mouse", species)) {
## do some more calculations
if(species=="Dormouse") return(paste0("You're sleeping until", x+y))
## do some more calculations
return(paste0("You're a mouse and will be eating for ", x^y, " more minutes."))
}
## some more ugly conditions
# ...
### finally
return("The end")
}
getout <- TRUE
# if getout==TRUE then the value of EXP, LOC, and FUN will be "OUTTA HERE"
# .... if getout==FALSE then it will be `3` for all these variables
EXP <- eval(expression({
1
2
if(getout) return("OUTTA HERE")
3
}))
LOC <- local({
1
2
if(getout) return("OUTTA HERE")
3
})
FUN <- (function(){
1
2
if(getout) return("OUTTA HERE")
3
})()
identical(EXP,LOC)
identical(EXP,FUN)
foo <- function() {
if (a) return(a)
b
}
# Add one to the result
result = x + 1
f = function (a, b) {
if (! precondition(a)) return() # same as `return(NULL)`!
calculation(b)
}
sign = function (num) {
if (num > 0) {
1
} else if (num < 0) {
-1
} else {
0
}
}
f = function (a, b) {
if (precondition(a)) calculation(b)
}
save_results = function (results, file) {
# … code that writes the results to a file …
invisible()
}
function(){
#do stuff
...
abcd
}
function(){
#do stuff
...
return(abdc)
}