[解決済み] Rubyで文字列の代わりにシンボルを使用するのはいつ?
質問
スクリプト内に同じ文字列が2つ以上ある場合、シンボルを使用したほうがよいでしょうか。
どのように解決するのですか?
TL;DR
単純な経験則では、内部識別子が必要なときは常にシンボルを使用することです。Ruby < 2.2 では、メモリリークを避けるために、シンボルは動的に生成されないときだけ使用します。
完全な答え
動的に生成される識別子に使用しない唯一の理由は、メモリに関する懸念です。
多くのプログラミング言語にはシンボルがなく、文字列のみであるため、コードの中で文字列も識別子として使用されるため、この質問は非常によくあることです。あなたが心配すべきなのは、どのシンボルが であることを意味します。 だけでなく を使用する必要がある場合 . 記号は識別するためのものです。この哲学に従えば、物事を正しく行うことができる可能性があります。
シンボルと文字列の実装には、いくつかの違いがあります。シンボルについて最も重要なことは、シンボルは 不変 . これは、決して値が変更されないことを意味します。このため、シンボルは文字列よりも高速にインスタンス化され、2つのシンボルを比較するようないくつかの操作も高速になります。
シンボルが不変であるということは、Rubyがシンボルを参照するたびに同じオブジェクトを使用し、メモリを節約することを可能にします。そのため、インタープリタが
:my_key
を読むたびに、それを再びインスタンス化する代わりにメモリから取り出すことができるのです。これは、毎回新しい文字列を初期化するよりも低コストです。
すでにインスタンス化されているすべてのシンボルのリストを得るには、コマンド
Symbol.all_symbols
:
symbols_count = Symbol.all_symbols.count # all_symbols is an array with all
# instantiated symbols.
a = :one
puts a.object_id
# prints 167778
a = :two
puts a.object_id
# prints 167858
a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!
puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.
Ruby2.2以前のバージョンでは、シンボルがインスタンス化されると、このメモリは
二度と解放されません。
. メモリを解放する唯一の方法は、アプリケーションを再起動することです。ですから、シンボルも使い方を誤るとメモリリークの大きな原因になります。メモリリークを発生させる最も簡単な方法は、メソッド
to_sym
を使うことです。このデータは常に変更されるため、ソフトウェアインスタンスではメモリの新しい部分が永遠に使われ続けることになります。Ruby 2.2 では
シンボルガベージコレクタ
が導入され、動的に生成されたシンボルを解放するようになったので、シンボルを動的に生成することで発生するメモリリークは気にならなくなりました。
質問にお答えします。
アプリケーションやスクリプトの中に同じ文字列が2つ以上ある場合、文字列の代わりにシンボルを使わなければならないというのは本当でしょうか?
もしあなたが探しているものが、コードの内部で使用される識別子であれば、シンボルを使用すべきです。出力を印刷するのであれば、たとえそれが複数回表示され、メモリ内に2つの異なるオブジェクトが割り当てられていたとしても、文字列を使用すべきなのです。
以下はその理由です。
- シンボルは文字列にキャストされるため、シンボルの印刷は文字列の印刷よりも遅くなります。
- シンボルは決して解放されないので、多くの異なるシンボルを持つことは、アプリケーションの全体的なメモリ使用量を増加させます。そして、コードからすべての文字列を同時に使用することはありません。
AlanDert による使用例
@AlanDert: %input{type: :checkbox} のようなものを何度も使用する場合。のようなものを何度も使う場合、チェックボックスとして何を使うべきでしょうか?
私:はい。
@AlanDert: でも、htmlページでシンボルを印刷するには、文字列に変換されるはずですよね。
入力のタイプとは何ですか?使用したい入力のタイプの識別子か、ユーザーに見せたい何かですか?
確かにそれは HTML コードになるのですが、あなたがそのコードを書いている時点では、識別子であることを意味しているのです。そのため、コード内で何度も繰り返し使用され、常に同じ文字列が識別子として使用されるため、メモリリークが発生することはありません。
それはそうと、文字列の方が速いかどうか、データで評価してみませんか?
これはそのために作った簡単なベンチマークです。
require 'benchmark'
require 'haml'
str = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: "checkbox"}').render
end
end.total
sym = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: :checkbox}').render
end
end.total
puts "String: " + str.to_s
puts "Symbol: " + sym.to_s
3つの出力
# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68
というわけで、smbolsを使う方がstringを使うよりも実は少し速いのです。なぜでしょうか?それはHAMLの実装方法によるものです。HAMLのコードを少しハックしてみないとわかりませんが、識別子の概念でシンボルを使い続ければ、アプリケーションはより速く、より信頼性の高いものになるでしょう。疑問が湧いたら、ベンチマークして答えを出しましょう。
関連
-
[解決済み】Ruby: 特定のバージョンのruby gemをインストールする方法は?
-
[解決済み】Ruby:kind_of? vs. instance_of? vs. is_a?
-
[解決済み] Rubyのswitch文の書き方
-
[解決済み] Rubyで配列に値が存在するかどうかを確認する方法
-
[解決済み] Rubyからシェルコマンドを呼び出す方法
-
[解決済み] Rubyでnilとemptyとblankを理解する方法
-
[解決済み] Rubyのattr_accessorとは何ですか?
-
[解決済み] gemのインストールで --no-ri --no-rdoc をデフォルトにするには?
-
[解決済み] シンボルをES6に導入する動機は何ですか?
-
[解決済み] リファレンス - このシンボルはPHPで何を意味するのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Rubyのメソッド'to_sym'は何をするのですか?
-
[解決済み] シンボルをES6に導入する動機は何ですか?
-
[解決済み] rvm use 2.0.0 --default を実行すると、"Warning! PATH is not properly set up" と表示される。
-
[解決済み] JSONファイルへの正しい書式での書き込み方法
-
[解決済み] Ruby: HTTP でファイルを multipart/form-data で投稿するには?
-
[解決済み] Ruby: 文字列の最初の文字を取得する方法
-
[解決済み] ruby の rescue 節に複数のエラークラスを DRY に渡す方法
-
[解決済み] doブロックと中括弧{}の使い分け
-
[解決済み] rspecでテストグループを無効にする?
-
[解決済み] raise "foo"`と`raise Exception.new("foo")` の違いは何ですか?