回答:
単純な経験則では、内部識別子が必要になるたびにシンボルを使用します。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.
2.2より前のRubyバージョンでは、シンボルがインスタンス化されると、このメモリは二度と解放されません。メモリを解放する唯一の方法は、アプリケーションを再起動することです。そのため、シンボルを誤って使用すると、メモリリークの主な原因にもなります。メモリリークを生成する最も簡単な方法はto_sym
、ユーザー入力データに対してメソッドを使用することです。このデータは常に変更されるため、メモリの新しい部分がソフトウェアインスタンスで永久に使用されます。Ruby 2.2は、動的に生成されたシンボルを解放するシンボルガベージコレクターを導入しました。そのため、動的にシンボルを作成することによって生成されるメモリリークは問題ではなくなりました。
あなたの質問に答える:
アプリケーションまたはスクリプトに同じ文字列が2つ以上ある場合、文字列ではなくシンボルを使用する必要があるのは本当ですか?
探しているものがコードで内部的に使用される識別子である場合、シンボルを使用する必要があります。出力を印刷する場合は、2つ以上のオブジェクトがメモリに割り当てられている場合でも、文字列を使用する必要があります。
ここに理由があります:
@AlanDert:hamlコードで%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
したがって、smbolを使用する方が実際には文字列を使用するよりも少し高速です。何故ですか?HAMLの実装方法によって異なります。確認するにはHAMLコードを少しハックする必要がありますが、識別子の概念でシンボルを使い続けると、アプリケーションの速度と信頼性が向上します。質問が発生した場合は、ベンチマークして回答を取得します。
簡単に言えば、シンボルは文字で構成される名前ですが、不変です。逆に、文字列は文字の順序付きコンテナであり、その内容を変更することができます。
2つの文字列を比較するには、すべての文字を調べる必要がある可能性があります。長さNの2つの文字列の場合、これにはN + 1の比較が必要になります(コンピューター科学者は "O(N)時間"と呼びます)。
def string_comp str1, str2
return false if str1.length != str2.length
for i in 0...str1.length
return false if str1[i] != str2[i]
end
return true
end
string_comp "foo", "foo"
しかし、:fooのすべての出現は同じオブジェクトを参照しているため、オブジェクトIDを調べることでシンボルを比較できます。これは1回の比較で実行できます(コンピューター科学者は「O(1)時間」と呼んでいます)。
def symbol_comp sym1, sym2
sym1.object_id == sym2.object_id
end
symbol_comp :foo, :foo
C ++では、「列挙」を使用して、関連する定数のファミリーを表すことができます。
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;
BugStatus current_status = CLOSED;
しかし、Rubyは動的言語であるため、BugStatus型を宣言したり、正当な値を追跡したりする必要はありません。代わりに、列挙値をシンボルとして表します。
original_status = :open
current_status = :closed
3.Rubyシンボルは一定の一意の名前です
Rubyでは、文字列の内容を変更できます。
"foo"[0] = ?b # "boo"
ただし、シンボルの内容は変更できません。
:foo[0] = ?b # Raises an error
Ruby関数にキーワード引数を渡すときは、記号を使用してキーワードを指定します。
# Build a URL for 'bug' using Rails.
url_for :controller => 'bug',
:action => 'show',
:id => bug.id
通常、ハッシュテーブルのキーを表すために記号を使用します。
options = {}
options[:auto_save] = true
options[:show_comments] = false
ここに私がcodecademyで見つけた素晴らしい文字列対シンボルのベンチマークがあります:
require 'benchmark'
string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
string_time = Benchmark.realtime do
1000_000.times { string_AZ["r"] }
end
symbol_time = Benchmark.realtime do
1000_000.times { symbol_AZ[:r] }
end
puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."
出力は次のとおりです。
String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.
ハッシュキー識別子として記号を使用する
{key: "value"}
シンボルを使用すると、メソッドを別の順序で呼び出すことができます
def write(file :, data :, mode: "ascii") #簡潔にするために削除 終わり 書き込み(データ:123、ファイル: "test.txt")
文字列として保持し、メモリを節約するためにフリーズ
label = 'My Label'.freeze
/
(の後strings
)をリンクから削除する必要があります。ここにあります:www.reactive.io/tips/2009/01/11/the-difference-between-ruby- symbols-and-strings