Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby Freezeメソッド–オブジェクトの可変性を理解する

オブジェクトが可変であるとはどういう意味ですか?

派手な言葉で混乱させないでください。「可変性 」は、オブジェクトの内部状態を変更できることを意味します。これは、凍結されたオブジェクトを除く、すべてのオブジェクトのデフォルトです。 、または特別なオブジェクトのリストの一部であるもの。

つまり、Rubyのすべてのオブジェクトが変更可能というわけではありません!

数字や記号、さらにはtrueには意味がありません またはfalse (オブジェクトでもあります)変更します。

数字の1は常に1になります。

ただし、他のオブジェクト、特に配列オブジェクトやハッシュオブジェクトなどのデータを格納することを目的としたオブジェクトは、パフォーマンス上の理由から変更できる必要があります。

代替手段は何ですか?

新しいコピーを作成できます 変更を加えたオブジェクトを削除してから、元のオブジェクトをそのままにして、この新しいオブジェクトを返します。

配列が不変の場合 配列の1つの要素だけを変更したい場合は、変更されなかった要素を含むすべてのデータをコピーする必要があります。

変更を加えるたびに100万(またはそれ以上)の要素配列をコピーする必要があると想像してみてください。どんなに小さくても構いません。あまり効率的ではありません…

とにかく。

Rubyで可変性がどのように機能するかをもう少し詳しく見てみましょう。

ポインタとしての可変性と変数

次の2つの組み合わせによって引き起こされるプログラミングエラーのカテゴリがあります。

  • ミュータブルオブジェクト。
  • 変数にはデータが直接含まれていませんが、このデータが保存されている場所への参照が含まれているという事実。

これらのエラーが現れる1つの方法は、変数を「エイリアス」しようとしたときです。

ここに例があります

name       = "Peter"
other_name = name

puts other_name
# "Peter"

この例では、両方のname およびother_name 同じ文字列オブジェクトへの参照が含まれています。この文字列の内容を表示または変更するために使用できます。

Ruby Freezeメソッド–オブジェクトの可変性を理解する

other_nameを処理すると、問題が発生します 文字列のコピーのように。

other_name[0] = 'T'

name       # "Teter"
other_name # "Teter"

両方の変数が同じ文字列を指しているため、「Peter」を「Teter」に変更しました。おそらく「ピーター」を維持するつもりだったので、それは問題です。

クローンオブジェクト

この問題に対処する1つの方法は、dupを使用することです。 メソッド。

これにより、Rubyにオブジェクトのコピーを提供するように指示されます。 cloneもあります メソッド。オブジェクトのコピーを提供するだけでなく、フリーズ状態とオブジェクトで定義されているシングルトンメソッドをコピーします。

例を見てみましょう

numbers = [1, 2, 3]

more_numbers = numbers.dup
more_numbers << 4

numbers      # [1, 2, 3]
more_numbers # [1, 2, 3, 4]

この例では、元のnumbersがどのようになっているのかを確認できます。 アレイは変更されませんでした。そのdupを削除してみてください 3行目に電話して、何が起こるかを確認してください🙂

Rubyフリーズメソッド

オブジェクトを不要な変更から保護するもう1つの方法は、オブジェクトを「フリーズ」することです。 freezeを使用すると、Rubyオブジェクトをフリーズできます。 メソッド。

オブジェクトがフリーズしているときに、このオブジェクトを変更しようとすると、RuntimeErrorが発生します。 例外。

注:frozen?を使用できます オブジェクトがフリーズしているかどうかを確認するメソッド。

animals = %w( cat dog tiger )
animals.freeze

animals << 'monkey'
# RuntimeError: can't modify frozen Array

覚えておくべきことの1つは、これは1つのオブジェクト、この例では配列自体のみをフリーズするため、アイテムを追加したり削除したりできないことです。ただし、配列内の文字列は固定されていないため、変更できます

animals[1][0] = 't'
# => ["cat", "tog", "tiger"]

文字列をフリーズする場合は、freezeを呼び出す必要があります それらの上に。このように:animals.each(&:freeze)

冷凍ストリングス

可変オブジェクト、特に文字列もパフォーマンスに影響を与えます。その理由は、大きなプログラムでは同じ文字列が複数回使用される可能性が高いためです。

Rubyは、2つの文字列が同じように見えても、つまり同じ「コンテンツ」を持っていても、すべての文字列に対して新しいオブジェクトを作成します。これはirbで簡単に確認できます。 object_idを使用する場合 メソッド。

ここに例があります

a = 'test'
b = 'test'

a.object_id # 76325640
b.object_id # 76317550

これらのオブジェクトは余分なメモリと余分なCPUサイクルを消費しているため、これは問題です。

Ruby 2.1以降、凍結された文字列を使用する場合 、Rubyは同じ文字列オブジェクトを使用します。これにより、同じ文字列の新しいコピーを作成する必要がなくなります。これにより、メモリがいくらか節約され、パフォーマンスがわずかに向上します。

Railsは拡張になります このため、凍結された文字列を使用します。たとえば、このPRを見てください。

これにより、Ruby開発チームは文字列を不変に移動することを検討し始めました。 デフォルトではオブジェクト。実際、数日前にリリースされたばかりのRuby 2.3には、プロジェクトでこれを有効にする2つの方法が含まれています。

1つは、# frozen_string_literal: trueを含めることです。 文字列を不変にしたいすべてのファイルの上部にあります。もう1つは、コマンドライン引数--enable=frozen-string-literalを使用することです。 。

デフォルトでは、不変の文字列はおそらくRuby3.0に到達します。

気が狂って、アプリ内のすべての文字列をフリーズし始めないでください。ある種の利点を確認するために何百回も使用される文字列に対してのみこれを実行する必要があります。 。そうは言っても、フリーズする可能性のある文字列を見つけるために使用できるツールは次のとおりです。

方法を知る

可変オブジェクト内のすべてのメソッドが実際にオブジェクトを変更するわけではありません。たとえば、gsubメソッドは新しい文字列を返し、元の文字列は変更されません。

これらのメソッドの一部には、代替バージョンがあります これにより、元のオブジェクトがインプレースで変更されます。これは多くの場合、より効率的です。これらのメソッドは、感嘆符!で終わることがよくあります。 それらの効果を示すために。

これらの「バング」メソッドの2つの例は、gsub!です。 およびmap!

注意

!で終わるメソッド 必ずしも「オブジェクトを変更するメソッド」であるとは限りません。

より一般的には、! 記号は「危険」を表すために使用されます。 1つの このうちexit! メソッド。終了ハンドラーを無視して、プログラムをすぐに終了します。

オブジェクトを変更し、!で終わらないメソッドもあります シンボル。例:deleteclearpushconcat 、その他多数。

まとめ

可変性は難しい問題になる可能性がありますが、この投稿を読んだことで、それに対処する準備がはるかに整いました。メソッドが何をしているのかわからない場合は、Rubyのドキュメントを確認してください。これは、問題を回避するのに役立ちます。

この記事がお役に立てば幸いです。共有してください 友達と一緒に楽しむことができるように それも。また、以下のニュースレターに参加して、このようなコンテンツがリリースされたときに見逃さないようにしてください。


  1. Rubyオブジェクトモデルを詳細に理解する

    ウィキペディアによると、オブジェクト指向プログラミング(OOP)は、「オブジェクト」の概念に基づくプログラミングパラダイムであり、データとコードを含めることができます。フィールド形式のデータ(多くの場合、属性またはプロパティと呼ばれます)と形式のコードです。手順の(多くの場合、メソッドとして知られています)。 Rubyは純粋なオブジェクト指向言語です。つまり、Ruby言語では、すべてがオブジェクトです。これらのオブジェクトは、文字列、数値、クラス、モジュールなどであるかどうかに関係なく、オブジェクトモデルと呼ばれるシステムで動作します。 。 Rubyはobject_idと呼ばれるメソッドを

  2. Rubyでの挿入ソートを理解する

    注:これは、Rubyを使用したさまざまなソートアルゴリズムの実装を検討するシリーズのパート4です。パート1ではバブルソート、パート2では選択ソート、パート3ではマージソートについて説明しました。 データを並べ替えるためのさまざまな方法を引き続き検討するため、挿入並べ替えに目を向けます。挿入ソートが好きな理由はたくさんあります!まず、挿入ソートは安定です。 、これは、等しいキーを持つ要素の相対的な順序を変更しないことを意味します。 インプレースアルゴリズムでもあります 、は、並べ替えられた要素を格納するための新しい配列を作成しないことを意味します。最後に、挿入ソートは、すぐにわかるように、実