在函数中显式调用return还是不行
前段时间, 我被 R核心团队的Simon Urbanek 斥责 (我相信)build议用户在函数结尾处明确调用return (他的评论已被删除): 
 foo = function() { return(value) } 
相反,他build议:
 foo = function() { value } 
可能在这样的情况下,它是必需的:
 foo = function() { if(a) { return(a) } else { return(b) } } 
 他的评论阐明了为什么不调用return除非严格需要是件好事,但是这被删除了。 
 我的问题是:为什么不调用更快或更好的return ,从而更好? 
问题是:为什么不(明确)调用返回更快或更好,从而更好?
 在R文档中没有这样的假设。 
 那个人的页面?'function'说: 
 function( arglist ) expr return(value) 
没有调用return会更快吗?
  function()和return()都是原始函数, function()本身返回最后的计算值,即使不包含return()函数。 
 调用return()作为.Primitive('return')与最后一个值作为参数将做同样的工作,但需要更多的一个电话。 所以这(通常)不必要的.Primitive('return')调用可以吸引额外的资源。 然而,简单的测量表明,由此产生的差异非常小,因此不能成为不使用明确收益的原因。 下面的图是从这样select的数据中创build的: 
 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 

上面的图片可能会在你的平台上略有不同。 根据测量数据,返回对象的大小没有任何差别,重复次数(即使按比例放大)只是非常小的差异,实际上用实际数据和实际algorithm计算出来的重复次数是无法计算的,脚本运行得更快。
不打电话回来更好吗?
  Return是清晰地devise例程应该结束的代码“离开”的好工具,跳出函数并返回值。 
 # here without calling .Primitive('return') > (function() {10;20;30;40})() [1] 40 # here with .Primitive('return') > (function() {10;20;30;40;return(40)})() [1] 40 # here return terminates flow > (function() {10;20;return();30;40})() NULL > (function() {10;20;return(25);30;40})() [1] 25 > 
这取决于程序员的策略和编程风格,他使用什么样的风格,他可以不使用return(),因为它不是必需的。
R核心程序员使用两种方法,即。 有和没有显式返回(),因为它可以find“基”function的来源。
很多时候只有return()被使用(无参数)返回NULL,以便有条件地停止函数。
作为标准的用户或使用R的分析人员看不出真正的差异,目前尚不清楚。
我的意见是这个问题应该是: 使用来自R实施的明确回报有没有危险?
或者,也许更好,用户编写函数代码应该总是问:函数代码中不使用显式返回(或将对象作为代码分支的最后一个叶返回)的效果是什么?
如果每个人都同意这一点
-  在函数体的结尾处不需要return
-  不使用return稍微快一点(根据@ Alan的testing,4.3微秒与5.1)
 我们是否应该在函数结束时停止使用return ? 我当然不会,我想解释为什么。 我希望听到其他人是否同意我的看法。 我很抱歉,如果这不是OP的直接答案,更像是一个长期的主观评论。 
 我不使用return主要问题是,正如Paul指出的那样,函数体中还有其他地方可能需要它。 如果你不得不在函数中间的某个地方使用return ,为什么不把所有的return语句都显式化呢? 我讨厌不一致。 另外我觉得代码读得更好; 可以扫描该function并轻松查看所有出口点和值。 
保罗使用这个例子:
 foo = function() { if(a) { return(a) } else { return(b) } } 
不幸的是,有人可以指出,它可以很容易地被重写为:
 foo = function() { if(a) { output <- a } else { output <- b } output } 
后者甚至符合一些程序编码标准,每个函数都提倡一个return语句。 我认为一个更好的例子可能是:
 bar <- function() { while (a) { do_stuff for (b) { do_stuff if (c) return(1) for (d) { do_stuff if (e) return(2) } } } return(3) } 
 使用单个return语句来重写会更困难:它需要多个break和一个复杂的布尔variables系统来传播它们。 所有这一切都说R的单一返回规则不能很好地发挥作用。所以,如果你需要在你的函数体的某些地方使用return ,为什么不能保持一致并在任何地方使用呢? 
我不认为速度论证是有效的。 当您开始查看实际执行某些操作的函数时,0.8微秒的差异就不算什么了。 我能看到的最后一件事情是打字less,但嘿,我不懒惰。
 看来,没有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 
____ 编辑 __ _ _ _ _ _ _ _ _ _ _ _ _ ___
 我进入其他基准( benchmark(fuu(x),foo(x),replications=1e7) ),结果是相反的…我会尝试在服务器上。 
 这是一个有趣的讨论。 我认为@ flodel的例子非常好。 不过,我认为这说明了我的观点(@koshke在评论中提到这一点), 当你使用命令而不是function性编码风格时 , return是有意义的 。 
 不要轻视这一点,但我会重写这样的foo : 
 foo = function() ifelse(a,a,b) 
 function风格避免了状态变化,如存储output的值。 在这种风格中, return是不合适的。  foo看起来更像是一个math函数。 
 我同意@ flodel:在bar使用一个错综复杂的布尔variables系统将不那么清晰,并且在return时没有意义。 是什么让bar顺利return陈述是它是写在一个迫切的风格。 事实上,布尔variables表示在function风格中避免的“状态”变化。 
 在function风格上重写bar真的很难,因为它只是伪代码,但是这个想法是这样的: 
 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. } 
  while循环将是最难重写的,因为它是由状态变化控制a 。 
 呼叫return造成的速度损失可以忽略不计,但通过避免函数式return和重写所获得的效率往往是巨大的。 告诉新用户停止使用return可能没有帮助,但引导他们到function风格将会得到回报。 
  @Paul return在命令式风格中是必须的,因为你经常想要在循环中的不同点退出函数。 function样式不使用循环,因此不需要return 。 在一个纯粹的function风格中,最后的调用几乎总是期望的返回值。 
 在Python中,函数需要return语句。 但是,如果以function样式对函数进行编程,则可能只有一个return语句:在函数结束时。 
 使用另一个StackOverflow文章中的示例,假设我们需要一个函数,如果给定x中的所有值都具有奇数长度,则返回TRUE 。 我们可以使用两种风格: 
 # Procedural / Imperative allOdd = function(x) { for (i in x) if (length(i) %% 2 == 0) return (FALSE) return (TRUE) } # Functional allOdd = function(x) all(length(x) %% 2 == 1) 
在function风格中,要返回的值自然落在函数的末尾。 再次,它看起来更像是一个math函数。
  @GSee ?ifelse中列出的警告肯定是有趣的,但我不认为他们试图劝阻使用这个函数。 事实上, ifelse具有自动向量化函数的优点。 例如,考虑一个稍微修改过的foo版本: 
 foo = function(a) { # Note that it now has an argument if(a) { return(a) } else { return(b) } } 
 这个函数在length(a)为1时工作正常。但是如果你用一个ifelse重写了foo 
 foo = function (a) ifelse(a,a,b) 
 现在foo可以工作在任何长度的。 事实上,当a是matrix时它甚至会起作用。 返回值与test相同的形状是一个有助于vector化的function,而不是一个问题。 
如果在方法末尾添加额外的语句,突然返回值是错误的:
 foo <- function() { dosomething() } 
 这将返回dosomething()的值。 
现在我们来到第二天,添加一个新行:
 foo <- function() { dosomething() dosomething2() } 
 我们希望我们的代码返回dosomething()的值,但是不再这样做。 
有了明确的回报,这变得非常明显:
 foo <- function() { return( dosomething() ) dosomething2() } 
我们可以看到,这个代码有一些奇怪的地方,并修复它:
 foo <- function() { dosomething2() return( dosomething() ) } 
 我觉得return是一个把戏。 作为一般规则,函数中最后一个expression式的值将成为函数的值 – 而这个通用模式在很多地方都可以find。 以下全部评估为3: 
 local({ 1 2 3 }) eval(expression({ 1 2 3 })) (function() { 1 2 3 })() 
 什么return不是真的返回一个值(这是做或不做),而是以不规则的方式“爆发”的function。 从这个意义上讲,它是R中最接近的GOTO语句(也有break和next)。 我很less使用return ,也不会在函数结尾使用。 
  if(a) { return(a) } else { return(b) } 
  …这可以被重写,就if(a) a else b更好的可读性和更less的curl。 这里根本不需要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") } 
一般来说,对许多回报的需求表明,这个问题要么是丑陋的,要么是结构严重的
<>
  return并不是真的需要一个函数来工作:你可以使用它来分解一系列要评估的expression式。 
 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) 
  return可以提高代码的可读性: 
 foo <- function() { if (a) return(a) b }