在 Ruby 中显式返回是一种好的风格吗?

从 Python 背景出发,当涉及到样式时,总是有一个“正确的方法”(一种“ Python”方法) ,我想知道 Ruby 是否也存在同样的方法。我一直在使用我自己的风格指南,但我正在考虑发布我的源代码,我希望它能遵守任何可能存在的不成文的规则。

在方法中显式键入 return是“ Ruby 方式”吗?我已经见识过了,但是有没有正确的方法呢?有没有正确的 时间来做这件事?例如:

def some_func(arg1, arg2, etc)
# Do some stuff...
return value # <-- Is the 'return' needed here?
end
83525 次浏览

没有。好的 Ruby 样式通常只对 提前回来使用显式的返回值。Ruby 非常重视代码极简主义/隐式魔术。

也就是说,如果一个明确的回报会使事情变得更清楚,或者更容易阅读,它不会伤害任何东西。

就像本说的。“ 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

问题在于你更喜欢哪种风格。如果您想要从方法中的某个位置返回,则必须使用关键字 return。

我个人使用 return关键字来区分我所调用的 功能性方法,即主要为返回值执行的方法和主要为副作用执行的 程序性方法。因此,在返回值很重要的方法中,获得一个额外的 return关键字来引起对返回值的注意。

在使用 打来的方法时,我使用了相同的区别: 函数方法使用括号,过程方法不使用括号。

最后但并非最不重要的是,我还将这种区别用于块: 函数块得到大括号,过程块(即“做”某事的块)得到 do/end

然而,我尽量不对它表示虔诚: 使用块、花括号和 do/end的优先级不同,我没有添加明确的括号来消除表达式的歧义,而是切换到另一种样式。方法调用也是如此: 如果在参数列表周围添加括号使代码更具可读性,那么我会这样做,即使所讨论的方法本质上是过程性的。

这个问题很老套,但是我还是要提出我的看法作为答案。

DR-您不必这样做,但是在某些情况下它可以使您的代码更加清晰。

尽管不使用显式的返回可能是“ Ruby 方式”,但对于使用不熟悉代码的程序员来说,这会让他们感到困惑,或者不熟悉 Ruby 的这个特性。

这是一个有点人为的例子,但是想象一下有一个这样的小函数,它将传递的数字加1,并将其赋给一个实例变量。

def plus_one_to_y(x)
@y = x + 1
end

这个函数是否应该返回一个值?真的很难说开发者是什么意思,因为它既分配了实例变量,也返回了分配的值。

假设很久以后,另一个程序员(可能不太熟悉 Ruby 是如何根据执行的最后一行代码返回的)来到这里,希望放入一些 print 语句进行日志记录,这个函数就变成了这个..。

def plus_one_to_y(x)
@y = x + 1
puts "In plus_one_to_y"
end

现在函数破坏了 如果需要返回值。如果没有什么需要返回值,那也没关系。很明显,如果在代码链的更下面的某个地方,调用 this 的对象期望返回一个值,那么它将失败,因为它没有得到它所期望的返回值。

现在真正的问题是: 有什么东西真的期望返回值吗?这东西到底有没有弄坏什么?它会在未来打破什么东西吗?谁知道呢!只有对所有调用进行完整的代码审查才会让您知道。

因此,至少对我来说,最佳实践方法是要么非常明确地表示如果有关系就返回某些内容,要么在无关紧要时根本不返回任何内容。

所以在我们的小 demo 函数的情况下假设我们想让它返回一个值它会被写成这样。

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% 清楚发生了什么?它实际上不会对代码的执行能力产生任何影响。

实际上,重要的是要区分:

  1. 函数——为返回值执行的方法
  2. 过程-为其副作用执行的方法

Ruby 没有一种本地化的方法来区分这些——这使得您很容易编写一个过程 side_effect(),而另一个开发人员决定滥用您的过程的隐式返回值(基本上将其视为一个不纯函数)。

为了解决这个问题,学学 Scala 和 Haskell,让你的 程序显式地返回 nil(在其他语言中也称为 Unit())。

如果你遵循这一点,那么使用明确的 return语法或不只是成为一个个人风格的问题。

进一步区分职能和程序:

  1. 复制 Jörg W Mittag 用花括号编写函数块和用 do/end编写过程块的好主意
  2. 调用过程时使用 (),而调用函数时不使用 ()

注意,Jörg W Mittag 实际上主张反过来——在过程中避免使用 ()——但这是不可取的,因为您希望副作用方法调用与变量清楚地区分开来,特别是当效率为0时。有关详细信息,请参阅 Scala 方法调用风格指南

我同意 Ben Hughes 的观点,也不同意 Tim Holt 的观点,因为这个问题提到了 Python 的权威方式,并询问 Ruby 是否有类似的标准。

是的。

这是该语言的一个众所周知的特性,因此任何希望在 Ruby 中调试问题的人都应该理所当然地希望了解这个特性。

样式指南 指出,您不应该在最后一个语句中使用 return。你仍然可以使用它 如果这不是最后一个的话。这是社区严格遵守的约定之一,如果您计划与任何使用 Ruby 的人协作,您也应该遵守这个约定。


也就是说,使用显式 return的主要理由是它会让来自其他语言的人感到困惑。

  • 首先,这并不完全是 Ruby 独有的,例如 Perl 也有隐式返回。
  • 其次,大多数人,这适用于来自 Algol 语言。其中大多数都是 “低层”而不是 Ruby,因此您必须编写更多的代码才能完成某些工作。

对于 java 中的方法长度(不包括 getter/setter) ,一种常见的启发式方法是 一个屏幕。在这种情况下,您可能没有看到方法定义,并且/或者已经忘记了从哪里返回。

另一方面,在 Ruby 中最好坚持使用 不到10行长方法。考虑到这一点,人们可能会奇怪为什么他必须多写约10% 的声明,当他们明确暗示。


因为 Ruby 没有 无效方法,而且一切都更简洁,所以如果使用显式的 return,那么只是增加了开销,没有任何好处。