Ruby のオブジェクト モデルは単純な単一継承ですが、モジュールを「ミックスイン」して共有動作を追加することができます。あなたの場合select
、モジュールに存在するメソッドを使用していますEnumerable
。このモジュールは、Array、Hash、および Range に混在しています。これにより、 などのクラス メソッドのインスタンスが得られますselect
。ここで列挙可能なメソッドの詳細を読むことができます: https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select
Range#select
考えてみれば、配列を返すのは理にかなっています。範囲から連続した値を選択していませんか? ブロックが true を返す任意の値を選択しています。これにより、範囲を返すことができなくなります。したがって、#select
ハッシュまたは Enumerable に混在する他のクラスで呼び出された場合でも、常に配列が返されます。
アップデート:
Enumerable が範囲から配列を返す方法を理解するには
混在するクラスを実装するには、クラスでメソッドEnumerable
を定義するだけです。#each
仮に Range を再実装したとしましょう:
class Range
include Enumerable # mixin
def initialize(first, last)
@number_range = first.upto last # this is an array of ints
end
def each(&block) # this methods returns an enumerable
@number_range.each &block
end
end
上記で、仮想範囲インスタンスを初期化できます。
@hypo_range = Range.new 1, 10
その上で列挙可能なメソッドを呼び出します。
@hypo_range.any? { |i| i == 5 } # => true
@hypo_range.select &:odd? # => [1,3,5,7,9]
Enumerable API にフックするように実装するだけでよいため#each
、オブジェクトのクラスが何であれ、Ruby はそれをどうするかを正確に認識しています。これは、新しい#each
メソッドで既に配列を反復処理しているためです! Enumerable はeach
、フードの下でメソッドを使用して、他のすべての列挙可能なメソッドを上に実装しany?
ます。select
find
その#each
メソッドは、オブジェクトのコレクションを反復処理する方法を Ruby に指示する場所です。Ruby がオブジェクトを反復処理する方法を認識すると、結果は既に配列になっています。
Range の Rubinius 実装
ここで、値に到達するまで値while
からループし、各反復でブロックに ing を使用することで Range が実装されていることがわかります。ブロックは結果を配列に収集します。これが、内部でそれを使用しているため、呼び出しから配列を取得する方法です。first
last
yield
Range#select
select
each
https://github.com/rubinius/rubinius/blob/master/core/range.rb#L118
いくつかのリソース: