来自 Python 背景,在风格方面总是有一种“正确的方式”(一种“Pythonic”方式),我想知道 Ruby 是否也存在同样的情况。我一直在使用自己的风格指南,但我正在考虑发布我的源代码,并且我希望它遵守任何可能存在的不成文规则。
在方法中显式输入 return
是“Ruby 方式”吗?我已经看到它有没有完成,但是有正确的方法吗?是否有合适的时间去做?例如:
def some_func(arg1, arg2, etc)
# Do some stuff...
return value # <-- Is the 'return' needed here?
end
旧的(和“已回答的”)问题,但我会投入两分钱作为答案。
TL;DR - 您不必这样做,但在某些情况下它可以使您的代码更加清晰。
尽管不使用显式返回可能是“Ruby 方式”,但对于使用不熟悉代码或不熟悉 Ruby 的此功能的程序员来说,这会让人感到困惑。
这是一个有点人为的例子,但是想象一下有一个像这样的小函数,它在传递的数字上加一,并将它分配给一个实例变量。
def plus_one_to_y(x)
@y = x + 1
end
这是否意味着是一个返回值的函数?很难说开发人员的意思是什么,因为它既分配了实例变量,又返回了分配的值。
假设很久以后,另一个程序员(可能不太熟悉 Ruby 如何根据执行的最后一行代码返回结果)出现并想要放入一些打印语句进行日志记录,并且函数变成了这个......
def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
end
现在,如果有任何东西需要返回值,该函数就会被破坏。如果没有任何东西期望返回值,那很好。很明显,如果在代码链的某个地方,调用它的东西期望返回值,它将失败,因为它没有得到预期的结果。
现在真正的问题是:真的有什么期望返回值吗?这是否破坏了某些东西?它会在未来破坏一些东西吗?谁知道!只有对所有调用进行完整的代码审查才能让您知道。
所以至少对我来说,最佳实践方法是要么非常明确地表明你正在返回一些重要的东西,要么在它不重要时什么都不返回。
所以在我们的小演示函数的情况下,假设我们希望它返回一个值,它会这样写......
def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
return @y
end
任何程序员都非常清楚它确实返回了一个值,而且他们更难在没有意识到的情况下破坏它。
或者,可以这样写,省略 return 语句......
def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
@y
end
但是为什么要省去返回这个词呢?为什么不把它放在那里,让它 100% 清楚发生了什么?它实际上不会影响您的代码的执行能力。
不会。好的 Ruby 风格通常只使用显式返回来提前返回。 Ruby 擅长代码极简主义/隐式魔法。
也就是说,如果显式返回会使事情变得更清晰或更易于阅读,那么它不会损害任何东西。
return
作为函数的提前退出已经具有重要的语义含义。
return
混淆为 EARLY EXIT 呢?
我个人使用 return
关键字来区分我所说的函数方法,即主要为返回值执行的方法和主要为执行的过程方法他们的副作用。因此,返回值很重要的方法,需要额外的 return
关键字来引起对返回值的注意。
我在调用方法时使用相同的区别:函数式方法有括号,而过程式方法没有。
最后但同样重要的是,我还将这种区别与块一起使用:功能块得到花括号,程序块(即“做”某事的块)得到 do
/end
。
但是,我尽量不要对此深信不疑:对于块、花括号和 do
/end
具有不同的优先级,我没有添加显式括号来消除表达式的歧义,而是切换到另一种样式。方法调用也是如此:如果在参数列表周围添加括号使代码更具可读性,我会这样做,即使所讨论的方法本质上是程序性的。
实际上,重要的是要区分:
函数 - 为其返回值执行的方法 过程 - 为其副作用执行的方法
Ruby 没有本地方式来区分这些 - 这使您容易编写过程 side_effect()
和另一个开发人员决定滥用您的过程的隐式返回值(基本上将其视为不纯函数)。
要解决此问题,请参考 Scala 和 Haskell 的书,并让您的过程显式返回 nil
(在其他语言中也称为 Unit
或 ()
)。
如果您遵循这一点,那么是否使用显式 return
语法只是个人风格的问题。
进一步区分函数和过程:
复制 Jörg W Mittag 用花括号编写功能块和使用 do/end 编写程序块的好主意 调用过程时,使用 (),而调用函数时,不要
请注意,Jörg W Mittag 实际上提倡相反的方式 - 避免对过程使用 ()
- 但这是不可取的,因为您希望将副作用方法调用与变量清楚地区分开来,尤其是当 arity 为 0 时。请参阅 Scala style guide on method invocation 了解细节。
function_a
的返回值,而 function_a
被写入调用(并且只能通过调用)procedure_b
,那么 function_a
真的是一个函数吗?它返回一个值,满足您对功能的要求,但它有一个副作用,满足程序的要求。
function_a
可以包含 procedure_...
调用树,实际上 procedure_a
可以包含 function_...
调用树。与 Scala 类似,但与 Haskell 不同,Ruby 无法保证函数没有副作用。
The style guide 声明,您不应在最后一条语句中使用 return
。您仍然可以使用它if it's not the last one。这是社区严格遵守的约定之一,如果您打算与任何使用 Ruby 的人合作,您也应该如此。
话虽如此,使用显式 return
的主要论据是它会让来自其他语言的人感到困惑。
首先,这并不完全是 Ruby 独有的。例如 Perl 也有隐式返回。
其次,这适用于大多数人来自 Algol 语言。其中大多数都比 Ruby“低级”,因此您必须编写更多代码才能完成任务。
java 中方法长度(不包括 getter/setter)的常见启发式方法是一个屏幕。在这种情况下,您可能看不到方法定义和/或已经忘记了您从哪里返回。
另一方面,在 Ruby 中,最好坚持使用方法 less than 10 lines long。鉴于此,人们会想知道为什么他必须多写约 10% 的陈述,而这些陈述是明确暗示的。
由于 Ruby 没有 void 方法,而且一切都更加简洁,因此如果使用显式 return
,则只会增加开销而没有任何好处。
我同意 Ben Hughes 的观点,但不同意 Tim Holt 的观点,因为这个问题提到了 Python 的明确方式,并询问 Ruby 是否有类似的标准。
这是该语言的一个众所周知的特性,任何希望在 ruby 中调试问题的人都应该合理地期望知道它。
return
关键字显然是一种糟糕的风格。
这是您最喜欢哪种风格的问题。如果要从方法中间的某个位置返回,则必须使用关键字 return。
正如本所说。 “ruby 方法的返回值是函数体中最后一条语句的返回值”这一事实导致 return 关键字在大多数 ruby 方法中很少使用。
def some_func_which_returns_a_list( x, y, z)
return nil if failed_some_early_check
# function code
@list # returns the list
end
if failed_check then nil else @list end
?这是真正的功能。
return
为代码添加了语义,为什么不呢?它几乎不是很冗长——我们不是在说 5 行对 3 行,只是多一个词。我希望至少在函数中(可能不在块中)看到return
,以便表达代码的实际作用。有时您必须返回 mid-function - 不要仅仅因为可以而忽略最后一行的最后一个return
关键字。我根本不喜欢冗长,但我喜欢一致性。side_effect()
并且另一个开发人员决定(ab)使用您的过程的隐式返回值。要解决此问题,您可以明确地使您的过程return nil
。