5

Scalaの利点の1つは、スコープを細かく制御できることです。次のような関数をネストできます。

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

ここでの問題は、fn1が少し威圧的に見え始めるかもしれないということです。Javaのバックグラウンドから来ているので、IDEの単一の「ページ」で表示できるように関数を十分に小さく保つことをお勧めします。

「現在はfn1でのみ使用されていますが、後でクラスの他の場所で役立つ可能性があります...」という理由に基づいて、fn1からfn12を削除することについてどう思いますか。

また、ネストされた関数をどこに配置するか(それらを呼び出すコードの前または後)を優先しますか?

4

6 に答える 6

7

一般に、実際のコードでは関数のネストはそれほど多くありません。これは、メソッドをシンプルかつ簡潔に保つという精神に反しています。このようなネストは主に、外部スコープのパラメーターの一部(再帰関数の内部ループなど)を使用するクロージャーに役立ちます。そのため、外部で宣言してこれらの引数を明示的に再渡すよりもクリーンです。

ネストされた関数は、それらを呼び出すコードの前に配置する必要があります。そうしないと、前方参照であり、コンパイルされません。(オブジェクト/クラスでは、それらを後に配置できますが、メソッドには配置できません。)

于 2012-07-08T20:32:07.767 に答える
5

1層のネストを利用するパターンがいくつかあります。

再帰。実装の詳細を非表示にするために使用されます(2つの別々のトップレベルメソッドに分離するよりもクリーンです)。

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 */
}

そして、ローカルブロックの暗黙の変換をシャドウイングするようなより難解なトリック。

これらの両方が必要な場合は、2回のネストを想定できます。それ以上のことはおそらくやり過ぎでしょう。これは主に、1つの方法でやりすぎをしているためです。メソッド内で定義されたすべての種類の変数の周りにクロージャの厄介な寄せ集めを用意するのではなく、独自のメソッドになることができるクリーンなインターフェイスで問題を細分化する方法を検討する必要があります。大きなメソッドはグローバル変数のようなものです。すべてが実装の詳細に依存しすぎて、追跡するのが難しくなります。何かがまともなインターフェースを持つようにするために適切な量の思考を行う準備ができている場合は、一度だけ必要な場合でも、それをトップレベルに持ち出すことを検討してください。あなたがそれほど難しいことを考えないのであれば、私の傾向は、インターフェースを汚染しないようにそれを中に残しておくことです。

いずれにせよ、必要な場所にメソッドを作成することを恐れないでください。たとえば、2つのコレクションがあり、それぞれがロジックの特定のポイントで同じ操作を実行する必要があるメソッドの奥深くにいるとします。あなたが1つか2つか3つの方法であるかどうか心配しないでください!必要な場所にメソッドを作成し、繰り返すのではなく呼び出すだけです。(同じ場所で複数のものを処理する必要がある場合は、リストとマッピングを作成することもできます。)

于 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

それは確かにかなり怖いようです!プライベートメソッドのスコープを微調整する場合は、次のように宣言できます。

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

scopeパッケージはどこにありますか。詳細については、忙しいJava開発者向けScalaガイドをご覧ください。

私は個人的に名前付きメソッド(def)をネストすることを避けていますが、無名関数(たとえば、継続渡しスタイルのプログラミングでのクロージャー)をネストすることは気にしません。

于 2012-07-08T20:24:58.523 に答える
0

入れ子関数は便利です(たとえば、再帰のヘルパー)。しかし、それらが多すぎる場合は、それらを新しいタイプに抽出してそれに委任することを妨げるものは何もありません。

于 2012-07-08T20:53:02.753 に答える