56

ルビーでは、ここに示すように使用することで、モジュールを混ぜることなくモジュール機能を利用できることを理解していますmodule_function。モジュールを混ぜずに関数を使用できるように、これがどのように役立つかがわかります。

module MyModule
  def do_something
    puts "hello world"
  end
  module_function :do_something
end

私の質問は、なぜこれらの両方の方法で関数を定義したいのかということです。

なぜ持っていないのですか

def MyModule.do_something

また

def do_something

どのような場合に、関数を混合したり、静的な方法として使用したりできると便利ですか?

4

3 に答える 3

49

Enumerableを考えてみてください。

これは、モジュールに含める必要がある場合の完璧な例です。クラスが を定義している場合、モジュール ( 、など)#eachを含めるだけで多くの利点が得られます。これは、モジュールを mixin として使用する場合の唯一のケースです。モジュールを含めるクラスで定義されたいくつかのメソッドに関してモジュールが機能を提供する場合です。これが一般的な唯一のケースであると主張できます。#map#select

「静的」メソッドの定義に関しては、より良いアプローチは次のようになります。

module MyModule
  def self.do_something
  end
end

に電話する必要はありません#module_function。私はそれが奇妙なレガシーなものだと思います。

これを行うこともできます:

module MyModule
  extend self

  def do_something
  end
end

...しかし、モジュールをどこかに含めたい場合はうまく機能しません。Ruby のメタプログラミングの機微を理解するまでは避けることをお勧めします。

最後に、あなただけの場合:

def do_something
end

...グローバル関数としてではなく、プライベートメソッドとして終了しますObject(Rubyには関数はなく、メソッドのみです)。2 つの欠点があります。まず、名前空間がありません。同じ名前の別の関数を定義すると、後で評価される関数が取得されます。第 2 に、 に関して機能を実装している場合#method_missing、プライベート メソッドを使用すると、Objectそれがシャドウされます。そして最後に、モンキーパッチObjectは単なる悪事です:)

編集:

module_function次のように使用できますprivate

module Something
  def foo
    puts 'foo'
  end

  module_function

  def bar
    puts 'bar'
  end
end

そうすれば、 を呼び出すことはできますが、 を呼び出すことはできSomething.barませんSomething.foo。この への呼び出しの後に他のメソッドを定義するとmodule_function、それらも混在せずに使用できるようになります。

ただし、2つの理由で好きではありません。まず、モジュールが混在していて「静的」メソッドを持っているということは、少し危険に思えます。有効なケースがあるかもしれませんが、それほど頻繁ではありません。私が言ったように、私はモジュールを名前空間として使用するか、それを混在させるかのどちらかを好みますが、両方ではありません。

次に、この例でbarは、 が混在するクラス/モジュールでも使用できますSomethingselfメソッドが使用して混合する必要があるか、使用しないで混合する必要がないため、これがいつ望ましいかはわかりません。

module_functionメソッドの名前を渡さずに使用することは、使用するよりもかなり頻繁に使用されると思います。privateとについても同様protectedです。

于 2012-07-18T22:27:47.790 に答える
16

Ruby ライブラリーが内部状態を (あまり) 使用しない機能を提供するのは良い方法です。したがって、(たとえば)sin関数を提供したいが、「グローバル」( ) 名前空間を汚染したくないObject場合は、それを定数 ( ) の下のクラス メソッドとして定義できますMath

ただし、数学アプリケーションを作成するアプリ開発者は、sin2 行ごとに必要になる場合があります。メソッドがインスタンス メソッドでもある場合は、Math(またはMy::Awesome::Nested::Library) モジュールを含めるだけで、直接呼び出すことができますsin(stdlib の例)。

それは、ライブラリをユーザーにとってより快適にすることです。ライブラリの機能をトップレベルで使用したい場合は、自分で選択できます。

ちなみに、(モジュールの最初の行で)module_functionを使用して、同様の機能を実現できます。extend self私の考えでは、見栄えが良くなり、理解が少し明確になります。

更新:詳細な背景情報は、このブログ記事.

于 2012-07-18T22:30:34.060 に答える
2

実際の例を見たい場合は、chronic gem をチェックしてください。

https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb

Handlers は、次の Parser クラスに含まれています。

https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb

彼は module_function を使用して、そのインスタンスの呼び出しメソッドを使用して、Handler から Handler の特定のインスタンスにメソッドを送信しています。

于 2013-12-09T19:25:48.717 に答える