10

配列が当然の選択であると思われるものに対して、なぜ ruby​​ が配列ではなく列挙子を返すのか、私は興味があります。例えば:

'foo'.class
# => String

ほとんどの人は、文字列を文字の配列と考えています。

'foo'.chars.class
# => Enumerator

では、なぜ String#chars は配列ではなく Enumerable を返すのでしょうか? 誰かがこれについて多くのことを考えて、列挙子の方が適切であると判断したと思いますが、その理由はわかりません。

4

6 に答える 6

7

配列が必要な場合は、を呼び出します#to_aEnumerableとの違いArrayは、一方が怠惰で、もう一方が熱心であるということです。これは、古き良きメモリ(遅延)とCPU(熱心)の最適化です。どうやら彼らは怠惰なことを選んだようです

str = "foobar"
chrs = str.chars
chrs.to_a # => ["f", "o", "o", "b", "a", "r"]
str.sub!('r', 'z')
chrs.to_a # => ["f", "o", "o", "b", "a", "z"]
于 2012-05-09T12:10:36.527 に答える
5
  1. 抽象化-何かが配列である可能性があるという事実は、多くのユースケースでは気にしない実装の詳細です。あなたがそうする人のために、あなたはいつでも.to_aEnumerableを呼び出してそれを手に入れることができます。

  2. 効率性-列挙子は、Rubyが要素のリスト全体を一度に作成する必要がないという点で怠惰ですが、必要に応じて一度に1つずつ作成できます。したがって、必要な数だけが実際に計算されます。もちろん、これはアイテムあたりのオーバーヘッドの増加につながるため、トレードオフになります。

  3. 拡張性-Enumerablecharsを返す理由は、それ自体が列挙子として実装されているためです。ブロックを渡すと、そのブロックは文字ごとに1回実行されます。つまり、たとえば.chars.each do ... end;の必要はありません。あなたはただすることができます.chars do ... end。これにより、文字列の文字に操作チェーンを簡単に構築できます。

于 2012-05-09T12:15:43.393 に答える
2

これは、1.9の精神に完全に準拠しています。可能な場合はいつでも列挙子を返すことです。String#bytes、String#lines、String#codepointsだけでなく、Array#permutationなどのメソッドもすべて列挙子を返します。

ruby 1.8では、String#to_aは行の配列になりましたが、メソッドは1.9でなくなりました。

于 2012-05-09T15:03:20.097 に答える
1

「ほとんどの人は文字列を文字の配列と考えています」...Cまたは他の言語のように考える場合のみ。私見、Rubyのオブジェクト指向はそれよりもはるかに進んでいます。ほとんどのArray操作はより似ている傾向があるEnumerableので、おそらくその方が理にかなっています。

配列はさまざまなインデックスへのランダムアクセスに最適ですが、特定のインデックスが文字列にアクセスすることはめったにありません。(特定のインデックスにアクセスしようとしている場合は、おそらく学校の仕事をしていると思います)

各文字を検査しようとしている場合、Enumerableは機能します。Enumberableを使用すると、、、、などにアクセスmapできeachますinject。置換には、文字列関数と正規表現もあります。

率直に言って、私は文字の配列に対する現実の必要性を考えることができません。

于 2012-05-09T13:05:26.180 に答える
0

実際、 'foo'.charsは、str内の各文字を指定されたブロックに渡すか、ブロックが指定されていない場合は列挙子を返します。

それをチェックしてください:

irb(main):017:0> 'foo'.chars
=> #<Enumerable::Enumerator:0xc8ab35 @__args__=[], @__object__="foo", @__method__=:chars>
irb(main):018:0> 'foo'.chars.each {|p| puts p}
f
o
o
=> "foo"
于 2012-05-09T12:13:06.000 に答える
0

多分 a stringin ruby​​ は変更可能ですか?そのArray場合、実際には明らかな選択ではありません。たとえば、長さが変わる可能性があります。しかし、それでも文字を列挙したいでしょう...

また、文字列の文字の実際のストレージを実際に渡したいとは思いませんよね? つまり、Ruby についてはあまり覚えていません (かなり前のことです) が、インターフェースを設計する場合は、.charsメソッド/属性/その他の「コピー」を配布するだけです。さて...毎回新しい配列を割り当てますか? それとも、文字列内の文字を列挙する方法を知っている小さなオブジェクトを返すだけですか? したがって、実装を非表示にします。

いいえ。ほとんどの人は、文字列を文字の配列とは考えていません。ほとんどの人は、文字列を文字列と考えています。ライブラリ/言語/ランタイムによって定義された動作で。実装を使用すると、抽象化ベルトの下にあるもので厄介ですべてプライベートになりたい場合にのみ知る必要があります。

于 2012-05-09T12:09:04.920 に答える