2015-12-26 5 views
7

文字列またはRuby 2.3のfrozen-string-literal: trueプラグマでRuby 2.2のfrozenメソッドを使用すると、関連するフリーズした文字列リテラルは、プログラム実行中に一度だけ評価されます。文字列が補間を持たないフリーズした文字列を評価する

#frozen-string-literal: true 
5.times{p "#{}".object_id} 

出力(別のオブジェクトを補間

70108065381260 
70108065381260 
70108065381260 
70108065381260 
70108065381260 

#frozen-string-literal: true 
5.times{p "".object_id} 

出力(同じオブジェクトID)を補間していない

次はこれを説明すると思われます私DS):このプロパティは、(すなわち、一度だけ評価されている)何を

70108066220720 
70108066220600 
70108066220420 
70108066220300 
70108066220180 
  1. と呼ばれているのですか?それは不変性とは異なるはずです。
  2. 文字列がこのようなプロパティを正しく持つようになる条件を理解していますか?これに言及している公式文書はどこにありますか?
  3. 補間された文字列を1回だけ評価する方法はありますか?

答えて

7
  1. Interning。文字列は、であると言われています。
  2. 完全ではありません。インタプリタが評価する前に文字列の値が何であるかを判断できるのは、もっと似ています。たとえば、次のように考えてください。

    5.times { puts "#{'foo'}".object_id } 
    

    補間が関係していてもidは同じです。

  3. いいえ。これは内部最適化です。 Object#freezeの要点は不変です。


UPDATE:のみリテラル文字列が内在化されます。これは明らかである hereです。

補間を担当するコードの部分が見つかりませんでした。だからなぜ"#{'foo'}"がリテラル文字列とみなされるのか分かりません。この変換が行われると、それは下位のパーサーレベルにあり、実際の処理の前に発生します。これは、String#freezerb_str_freezeにマップされ、opt_str_freezeを呼び出さないという事実から明らかです。

+0

あなたの回答は正しいようです。Rubyの動作(あなたの答えではない)が私を混乱させています。 "通訳者は#{'foo'}'を決めることができますが、 '#{} 'は決めることができませんか?後者はもっと簡単です。 – sawa

+1

@sawaはまだ分かりませんが、コードを調べます。私の推測では、誰もそれを使用しないので、単に "#{}"のケースを扱わなかったでしょう。 – ndn

+0

私はあなたの答えが好きですが、あなたや他の人が2に完全な答えを出すのを少し待っています。 – sawa

-1

"Frozen"は、文字列が複数回評価されるかどうかについてのものではありません。それは、あなたが正しいことです、変更可能性についてです。

文字列リテラルは、と評価された場合、と評価されます。

評価するのは、ループではなく、一度だけ実行されるソースコードの行に挿入する方法です。ループ内の文字列リテラル(またはソースコードの他の部分)は、プログラムフローでそのソースコード行が実行されるたびに常に評価されます。

これは、一度評価されると、フリーズ/不変であるかどうかとはまったく別物です。

許容される回答は誤解を招くようなものです。インタビュアーが評価する前に文字列の値が何であるかを判断できるのは、もっと似ている」いいえ。どういたしまして。評価する必要があります。文字列が固定されていれば、それが評価されると、メモリ内の同じ位置と同じobject/object_id(同じことを表す2つの方法)が、他のすべての同等の文字列と同じになります。しかし、補間の有無にかかわらず、まだ評価中です。

(補間なしでは、文字列リテラルの '評価'は非常に速いです)単純な補間では、通常はかなり速いです。もちろん、補間を使用して高価なメソッドを呼び出しても構いません。

補間なしでは、私はそれについて全く心配しません。補間では、補間が十分に高価だと思うなら、ループ内でそれをしたくないのです - それを回避する唯一の方法は、ループ内で行うのではなく、ループ外に一度作成することです。

Rubyのドキュメントでは、「リテラル文字列」ではなく「文字列リテラル」を使用している可能性があります。 "文字列リテラル"は、ソースコード内のバイトによって作成された任意の文字列です(''""%Q[]、またはルビのソースコードに文字列リテラルを作成するその他の方法を使用)。補間の有無にかかわらず。

したがって、どのような種類の文字列は文字列リテラルによって作成されたではありませんか?たとえば、ファイルやネットワークからバイト単位で読み込んだ文字列です。または、既存の文字列を受け取り、some_string.dupのようにコピーを返すメソッドを呼び出して作成された文字列。 "文字列リテラル"とは、外部入力から読み込むのではなく、文字通りソースコードで作成された文字列を意味します。 http://ruby-doc.org/core-2.1.1/doc/syntax/literals_rdoc.html

+1

Ofc frozenは、不変性を示します。 OPは弦楽器のインターンを凍らせることを求めていた。解析があり、実行時の評価があります。 [ロジックのフォークはランタイム評価の前に発生する](https://github.com/ruby/ruby/blob/22d8481f080ce4eb758803ad1f60273b6c3a10ad/compile.c#L4796)、これは私が心に留めていたものです。補間のパフォーマンスは、質問と何が関係していますか?ドキュメンテーションとコードは、リテラル文字列がインターンされていると言っています。あなたのリテラル文字列の定義が正しい場合、補間に巨大なバグがあります...補間するものとして、 – ndn

+0

*「外部入力」*を追加する補間ソートは何でもかまいません。ここで重要なのは静的です。 – ndn

+0

補間にバグはありません。同じバイトを持つ2つのフリーズされた文字列は同じobject_idを持ち、実際には1つの文字列になります。文字列の一方または両方が補間で作成されているかどうかは関係ありません。バイトが同一である場合、それらは同じ文字列です。それが「インターン」の意味です。私はここでの混乱の本質を理解しているかどうか分からない。文字列リテラルは、補間を使用するかどうかにかかわらず、 "引用符"(または同等のもの)をソースコード内に作成した文字列です。文字列リテラルで作成されなかった文字列が文字列リテラルに補間される場合。 – jrochkind

関連する問題