在Ruby中显式返回是不错的风格?

Sas*_*gov 149 ruby coding-style return-value

来自Python背景,在风格方面总是有"正确的方法"("Pythonic"方式),我想知道Ruby是否存在相同的情况.我一直在使用自己的风格指南,但我正在考虑发布我的源代码,并且我希望它遵守可能存在的任何不成文的规则.

return在方法中明确键入是"Ruby方式" 吗?我已经看到它有没有完成,但有没有正确的方法呢?是否有合适的时机去做?例如:

def some_func(arg1, arg2, etc)
  # Do some stuff...
  return value # <-- Is the 'return' needed here?
end
Run Code Online (Sandbox Code Playgroud)

Tim*_*olt 218

旧的(和"回答")问题,但我会把我的两分钱作为答案.

TL; DR - 您没有必要,但它可以使您的代码在某些情况下更加清晰.

虽然不使用显式返回可能是"Ruby方式",但是对于使用不熟悉的代码或不熟悉Ruby的这个特性的程序员来说,这会让人感到困惑.

这是一个有点人为的例子,但成像有一个像这样的小功能,它会增加一个传递的数字,并将其分配给一个实例变量.

def plus_one_to_y(x)
    @y = x + 1
end
Run Code Online (Sandbox Code Playgroud)

这是否意味着是一个返回值的函数?很难说开发人员的意思是什么,因为它既分配了实例变量,又返回分配的值.

假设很久以后,另一个程序员(可能不熟悉Ruby基于最后一行代码执行返回的方式)来了,并希望输入一些用于日志记录的打印语句,该函数就变成了这个......

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
end
Run Code Online (Sandbox Code Playgroud)

现在的功能被破坏如果有什么需要一个返回值.如果没有人期望返回值,那很好.显然,如果代码链的某个地方更远,那么调用它的东西就是期望返回的值,它会失败,因为它没有回到它预期的状态.

现在真正的问题是:做了什么确实期望返回值吗?这件事有没有破坏?它将来会破坏什么吗?谁知道!只有对所有通话的完整代码审核才会通知您.

所以至少对我来说,最佳实践方法是要么非常明确地表示如果重要的话你要归还某些东西,要么在没有的时候根本不归还.

因此,在我们的小型演示函数的情况下,假设我们希望它返回一个值,它将被写成这样......

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    return @y
end
Run Code Online (Sandbox Code Playgroud)

并且任何程序员都会非常清楚它确实会返回一个值,并且更难以在没有意识到的情况下打破它.

或者,可以像这样写它并省略返回声明......

def plus_one_to_y(x)
    @y = x + 1
    puts "In plus_one_to_y"
    @y
end
Run Code Online (Sandbox Code Playgroud)

但是为什么要把这个词留下来呢?为什么不把它放在那里,让它100%清楚发生了什么?它实际上对您的代码执行能力没有任何影响.

  • 如果"return"这个词为代码增加了语义含义,为什么不呢?它几乎不是很冗长 - 我们不是说5行与3行,只是再说一个字.我更喜欢至少在函数中看到`return`(也许不在块中),以便表达代码实际上做的事情.有时你必须返回mid-function - 不要因为你可以在最后一行留下最后一个`return`关键字.我根本不喜欢冗长,但我赞成一致性. (25认同)
  • 虽然这是真的,但是对于代码来说是可读的很重要,在我看来,避免使用编程语言的一个众所周知的特性来支持冗长是不好的做法.如果开发人员不熟悉Ruby,那么在触摸代码之前他们应该熟悉.我发现,为了将来某些非Ruby开发人员必须做某事的事件,我必须增加代码的混乱,这有点愚蠢.我们不应该将语言缩减到最低的共同标准.Ruby的一部分美妙之处在于我们不必使用5行代码来说出只需要3行的代码. (15认同)
  • 有趣的一点.我想我在问这个问题时遇到了类似的情况,原始开发人员在他们的代码中使用隐式返回值,并且很难理解发生了什么.感谢您的回答! (6认同)
  • 谷歌搜索隐含的回报时,我发现了这个问题,因为我刚被这个烧毁了.我在函数的末尾添加了一些逻辑,隐含地返回了一些东西.大多数调用它并不关心(或检查)返回的值,但有人做了 - 但它失败了.幸运的是,至少它出现在一些功能测试中. (6认同)
  • 这是一个很好的答案.但是它仍然存在一种风险,即你编写一个Ruby方法,意图是一个过程(也就是函数返回单元),例如`side_effect()`,另一个开发人员决定(ab)使用过程的隐式返回值.要解决这个问题,你可以明确地让你的程序`return nil`. (6认同)
  • 还有另一种方法可以确保人们不会滥用您的隐含返回值:记录您的方法.总是写出该方法应该返回的内容. (4认同)
  • 我同意可读性很重要,但如果一个函数应该有一个返回值,**这就是**的规格.隐式返回是标准的ruby并且应该被使用,除非它没有意义(早期返回,或者意外或非常复杂的事情) (4认同)
  • IMO糟糕的推理.您不会为不懂语言的人编写代码.下一步是什么?"让我们不要在haskell中使用> @>!对于那些不懂哈斯克尔的人来说,这并不明显!"?是的,新手会破坏现有代码.这是正常的和预期的.这是(只有一个原因)为什么你有测试. (4认同)
  • +1这是一个非常好的答案,为什么返回显式值确实增加了清晰度和安全性. (3认同)
  • @apeiros是的.故意忽略语言的独特性是错过了语言的重点. (2认同)

Ben*_*hes 66

不.好的Ruby风格通常只会使用显式返回来提前返回.Ruby在代码极简主义/隐含魔法方面很重要.

也就是说,如果一个明确的回报会使事情更清晰,或更容易阅读,那么它不会伤害任何东西.

  • 如果它导致混淆极端主义,那么代码极简主义的意义何在? (110认同)
  • @jazzpi如果你必须大量记录你的代码,以便你很好地理解你不是在练习极简主义,那你就练习[code golf](https://en.wikipedia.org/wiki/Code_golf). (25认同)
  • @DevonParsons究竟怎么会有人把最后一行的'return`混淆为最早退出? (10认同)
  • 作为一个在工作中开始学习 Ruby 的人,有时会因为 Ruby 中存在如此多的“魔法位”而感到非常恼火。 (4认同)
  • 排除最终的返回结果并不令人困惑,将其包含在内也令人困惑-作为Ruby开发人员,`return`作为函数的早期出口已经具有重要的语义含义。 (2认同)

Jör*_*tag 31

我个人使用return关键字来区分我称之为功能方法的方法,即主要针对其返回值执行的方法,以及主要针对其副作用执行的程序方法.因此,返回值很重要的方法,获取额外的return关键字以引起注意返回值.

我在调用方法时使用相同的区别:函数方法获取括号,而过程方法则没有.

最后但并非最不重要的是,我也使用块的区别:功能块获得花括号,程序块(即"做"某事的块)得到do/ end.

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


Ale*_*ean 13

其实重要的是区分:

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

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

要解决这个问题,请从Scala和Haskell的书中删除,并明确返回您的过程nil(aka Unit()其他语言).

如果您遵循这一点,那么使用显式return语法或不仅仅是个人风格的问题.

进一步区分功能和程序:

  1. 复制JörgWMittag的好主意,用花括号和程序块来编写功能块 do/end
  2. 当您调用过程时,请使用(),而在调用函数时,请不要

需要注意的是约尔格W¯¯米塔格实际上主张的其他方式-避免()S表示程序-而是因为你想一边实现方法调用从变量清晰可辨,尤其是当元数为0.见,这不是明智的方法调用Scala的风格指南为细节.

  • 你是对的Devon - `function_a`可以包含一个`procedure _...`调用树,因为`procedure_a`确实可以包含一个`function _...`调用树.像Scala一样,但与Haskell不同,Ruby中无法保证函数不会产生副作用. (2认同)

ndn*_*kov 7

样式指南指出,您不应该return在最后一个声明中使用.如果它不是最后一个,你仍然可以使用它.这是社区严格遵守的惯例之一,如果您计划与使用Ruby的任何人合作,您也应如此.


话虽这么说,使用显式returns 的主要论点是,对于来自其他语言的人来说,它会让人感到困惑.

  • 首先,这不是Ruby独有的.例如,Perl也有隐式返回.
  • 其次,这适用的大多数人来自Algol语言.其中大多数都比Ruby更"低级",因此您必须编写更多代码才能完成某些任务.

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

另一方面,在Ruby中,最好坚持使用长度小于10行的方法.考虑到这一点,人们会想知道为什么当明确暗示时,他必须多写10%以上的陈述.


由于Ruby没有void方法,而且一切都更加简洁,如果你使用显式returns ,你只是增加了开销,没有任何好处.

  • 有时约定仍然是一个坏主意。它是一种依赖于魔法的风格约定,使得返回类型难以猜测。除了节省 7 次击键之外没有任何优势,并且与几乎所有其他语言都不一致。如果 Ruby 曾经进行过 Python 3 风格的整合和简化,我希望隐式 *anything* 是第一个被砍掉的。 (2认同)
  • 除了显然它实际上并没有使事情更容易阅读!魔法和可理解性不是一回事。 (2认同)