29

文字列と記号の理論的な違いを理解しています。シンボルは概念、名前、識別子、ラベル、キーを表すものであり、文字列は文字の袋であることを理解しています。文字列は可変で一時的であり、シンボルは不変で永続的であることを理解しています。テキスト エディタでシンボルが文字列と異なって見える点も気に入っています。

私が気になるのは、実際に言えば、シンボルは文字列に非常に似ているため、文字列として実装されていないという事実が多くの頭痛の種を引き起こしているということです。他の有名な「同じだが異なる」対である Float と Fixnum とは異なり、ダックタイピングや暗黙の強制さえサポートしていません。

もちろん、最大の問題は、JSON や HTTP CGI などの他の場所から Ruby に取り込まれるハッシュが、シンボル キーではなく文字列キーを使用することです。そのため、Ruby プログラムはこれらを事前に変換するか、ルックアップ時に変換する必要があります。が存在するだけでHashWithIndifferentAccess、Rails やその他のフレームワークで広く使用されていることは、ここに問題があることを示しています。

シンボルが凍結された文字列であってはならない実際的な理由を誰か教えてもらえますか? 「それが常に行われてきた方法だから」(歴史的)または「シンボルは文字列ではないため」(質問を懇願する)以外。

次の驚くべき動作を考えてみてください。

:apple == "apple"  #=> false, should be true

:apple.hash == "apple".hash #=> false, should be true

{apples: 10}["apples"]  #=> nil, should be 10

{"apples" => 10}[:apples]  #=> nil, should be 10

:apple.object_id == "apple".object_id #=> false, but that's actually fine

次世代の Rubyist の混乱を軽減するために必要なのは、次のことだけです。

class Symbol < String
  def initialize *args
    super
    self.freeze
  end

(そして他の多くのライブラリレベルのハッキングですが、それでもそれほど複雑ではありません)

以下も参照してください。

class Symbol < String更新: Matz はここで非常によく主張していると思います: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192 (これを掘り下げてくれた Azolo に感謝します。また、マッツの最終的な撤回)。

4

6 に答える 6

9

この回答は私の元の回答とは大幅に異なりますが、Ruby メーリング リストでいくつかの興味深い スレッドに遭遇しました。(どちらも読みやすい)

そのため、2006 年のある時点で、matz はSymbolクラスを として実装しましたSymbol < String。次に、Symbol可変性を取り除くためにクラスが取り除かれました。したがって、 aSymbolは実際には不変Stringでした。

ただし、元に戻しました。あげた理由は

DuckTyping には非常に反対ですが、人々はクラスで大文字小文字を使用する傾向があり、Symbol < String は深刻な問題を引き起こすことがよくあります。

したがって、あなたの質問に対する答えはまだです: aSymbolは a のようなものStringですが、そうではありません。
問題は、 aが であってSymbolはならないということStringではなく、歴史的にそうではなかったということです。

于 2012-06-18T15:52:02.007 に答える
5

完全な答えはわかりませんが、大部分は次のとおりです。

シンボルがハッシュ キーに使用される理由の 1 つは、特定のシンボルのすべてのインスタンスがまったく同じオブジェクトであることです。これは:apple.id、値を渡さなくても、常に同じ値を返すことを意味します。一方、"apple".id新しい文字列オブジェクトが作成されるため、毎回異なる ID が返されます。

その違いが、ハッシュ キーにシンボルが推奨される理由です。シンボルを使用する場合、オブジェクトの等価性テストを行う必要はありません。オブジェクト ID に直接短絡することができます。

于 2012-06-18T15:09:02.767 に答える
1

別の考慮事項は、それ"apple".each_charは理にかなっていますが、そうで:apple.each_charはありません。文字列は「文字の順序付きリスト」ですが、シンボルは明示的な値を持たないアトミック データポイントです。

HashWithIndifferentAccessこれは、Ruby シンボルが 2 つの異なる役割を果たしていることを実際に示していると言えます。シンボル(本質的には他の言語の列挙型に似ています) とインターンされた文字列(これらは本質的にプリエンプティブな最適化であり、Ruby が解釈されるという事実を補うため、インテリジェントな最適化コンパイラの利点がありません。)

于 2012-06-19T23:47:06.750 に答える
0

その基本は次のとおりです。これらは真実であってはなりません。

:apple == "apple"  #=> false, should be true

:apple.hash == "apple".hash #=> false, should be true

シンボルは常に同じオブジェクトですが、テキストはそうではありません。

于 2012-06-18T16:05:57.673 に答える
0

この回答を参照してください: https://stackoverflow.com/a/6745253/324978

主な理由: パフォーマンス (シンボルは整数として格納され、ガベージ コレクションは行われません) および一貫性 (:admin:adminは常に同じオブジェクトを指しますが、その保証は"admin"あり"admin"ません) など。

于 2012-06-18T15:12:20.023 に答える
0

String が Symbol を継承できるとしたら、それは多くの機能を追加する (変更する) ためです。しかし、変更が必要なすべての状況で失敗するため、シンボルを文字列として「として」使用することはできません。

いずれにせよ、上で述べたように、string == シンボルは、上で提案したように決して true を返してはなりません。これについて少し考えてみると、サブクラスのインスタンスも考慮するクラスで == の合理的な実装があり得ないことに気付くでしょう。

于 2012-06-20T08:46:18.153 に答える