5

Scala 的优点之一是它使您可以很好地控制范围。你可以嵌套这样的函数:

def fn1 = {
  def fn11 = {
    ...
  }
  def fn12 = {
    ...
    def fn121 = {
      ...
    }
  }
  ...
  def fn13 = {
    ...
  }
}

这里的问题是 fn1 可能开始看起来有点吓人。来自 Java 背景,建议我们保持函数足够小,以便在 IDE 中的单个“页面”上查看。

根据以下推理,您如何将 fn12 从 fn1 中取出:“它现在仅在 fn1 中使用,但它可能会在以后在课堂上的其他地方有用......”

此外,您是否会偏好放置嵌套函数的位置 - 在调用它们的代码之前或之后?

4

6 回答 6

7

一般来说,我在实际代码中看不到那么多函数嵌套。它违背了保持方法简单和简洁的精神。这种嵌套主要用于闭包,您将使用外部范围的一些参数(例如递归函数的内部循环),因此它比在外部声明它并且必须显式地重新传递这些参数更干净。

您必须将嵌套函数放在调用它们的代码之前,否则它是前向引用并且不会编译。(在对象/类中,您可以将它们放在后面,但不能放在方法中。)

于 2012-07-08T20:32:07.767 回答
5

有一些模式可以利用一层嵌套。

递归,它用于隐藏实现细节(并且比分成两个单独的顶级方法更干净):

def callsRecursive(p: Param): Result = {
  def recursive(p: Param, o: OtherParam, pr: PartialResult = default): Result = {
    ...
  }
}

范围安全的不要重复自己:

def doesGraphics(p: Point) {
  def up(p: Point): Point = // ...
  def dn(p: Point): Point = // ...
  def lf(p: Point): Point = // ...
  def rt(p: Point): Point = // ...
  /* Lots of turtle-style drawing */
}

还有更深奥的技巧,例如隐藏本地块的隐式转换。

如果你需要这两个,我可以设想嵌套两次。更多的可能是矫枉过正,主要是因为你可能让一种方法做得太多。您应该考虑如何使用干净的接口细分问题,然后这些接口可以成为它们自己的方法,而不是在方法中定义的各种变量周围有一个混乱的大杂烩。大方法就像全局变量:一切都变得过于依赖于实现的细节,而且难以跟踪。如果您已准备好进行适当的思考以使某些东西具有像样的界面,即使您只需要一次,那么请考虑将其带到顶层。如果您不打算那么努力,我倾向于将其留在内部以避免污染界面。

无论如何,不​​要害怕在任何你需要的地方创建一个方法。例如,假设您发现自己深陷于具有两个集合的某个方法中,每个集合都必须在逻辑中的特定点对它们执行相同的操作。不要担心,如果你是一两个或三个方法的深度!只需在需要的地方创建方法,然后调用它而不是重复自己。(请记住,如果您只需要在同一个地方处理几件事情,创建列表和映射是一种替代方法。)

于 2012-07-08T23:43:46.400 回答
3

如果您有一个像您描述的那样的顶级功能,它可能会做很多事情。

如果是这种情况,TDD 也有助于做出决定:一切仍然容易测试。

如果我得出的结论是这实际上是这种情况,我会重构以将内部函数作为依赖项取出,并使用它们自己的测试。

最终结果是我非常有限地使用了函数定义中定义的函数......我还对方法大小设置了更严格的限制:java 中大约 10-15 行,在 scala 中甚至更少,因为它不那么冗长。

我将内部函数主要放在外部方法的顶部,但这并不重要,因为它太短了。

于 2012-07-08T20:30:29.517 回答
2

我认为始终使用最低能见度是最佳实践。如果不同的函数需要嵌套函数,无论如何都可以移动它。

于 2012-07-08T20:24:05.293 回答
0

嵌套函数很有用(例如递归中的助手)。但是,如果它们太多,那么没有什么能阻止你将它们提取到一种新类型中并委托给它。

于 2012-07-08T20:53:02.753 回答
0

这看起来确实很吓人!如果要精细控制私有方法的范围,可以将它们声明为

private[scope] def fn12 = { ... } 

包在哪里scope。您可以在忙碌的 Java 开发人员 Scala 指南中阅读更多内容。

我个人避免嵌套命名方法(def),而我不介意嵌套匿名函数(例如,连续传递风格编程中的闭包)。

于 2012-07-08T20:24:58.523 回答