Spis treściKliknij link, aby przejść do wybranego miejsca
Ta treść została automatycznie przetłumaczona z ukraińskiego.
Na początku trzeba zrozumieć, czym jest immediate value oraz reference w Ruby.
Bezpośrednia wartość (immediate value) w języku programowania to wartość, która jest przechowywana bezpośrednio w zmiennej lub obiekcie, bez odniesienia do innego obszaru pamięci. Może to być liczba, symbol, true, false lub nil. Na przykład, gdy przypisujesz liczbę do zmiennej, to jest to bezpośrednia wartość.
Referencja (reference) wskazuje na obszar pamięci, w którym przechowywany jest obiekt. Obiekty, które zazwyczaj są przechowywane za pomocą referencji, obejmują łańcuchy, tablice, hashe i obiekty klas. Gdy pracujesz z obiektem za pomocą referencji, tak naprawdę pracujesz z obszarem pamięci, w którym przechowywany jest sam obiekt.
W poście o przypisaniu zmiennej w ruby omówiliśmy koncepcję referencji (reference). Ale nie omówiliśmy bezpośrednich wartości.
Bezpośrednie wartości w Ruby
Bezpośrednia wartość to wartość, która jest przechowywana bezpośrednio w zmiennej, a nie przez odniesienie do obiektu. Ale jest jeden aspekt, który osobiście mnie trochę zmylił. W Ruby nawet dla bezpośrednich wartości zmienne mają object_id, ale wskazują one na konkretne miejsce w pamięci, gdzie przechowywana jest wartość, a nie na obiekt, jak w przypadku referencji. To znaczy, w przypadku bezpośrednich wartości object_id nie wskazuje na obiekt w pamięci, a po prostu identyfikuje konkretną wartość, która jest przechowywana bezpośrednio w zmiennej. Tak, w Ruby nie wszystko jest obiektem.
Cytat z apidock:
object_id() public Zwraca całkowity identyfikator dla obj. Ta sama liczba będzie zwracana przy wszystkich wywołaniach object_id dla danego obiektu, a żadne dwa aktywne obiekty nie będą dzielić id. Uwaga: niektóre obiekty klas wbudowanych są ponownie używane w celu optymalizacji. Dotyczy to bezpośrednich wartości i zamrożonych literałów łańcuchowych. Bezpośrednie wartości nie są przekazywane przez referencję, ale są przekazywane przez wartość: nil, true, false, Fixnumy, symbole i niektóre liczby zmiennoprzecinkowe.
Te wartości są przechowywane bezpośrednio w zmiennych i nie mogą być zmieniane przez odniesienie do obiektu. Są najbardziej efektywnym sposobem przechowywania danych w pamięci, ponieważ nie wymagają przydzielania pamięci dla obiektu. Zrobiono to w celu optymalizacji pamięci. Nie ma sensu tworzyć nowych obiektów dla każdego nil. Więc zróbmy trochę zabawy z IRB.
Łańcuch to obiekt.
a = 'hehe' b = 'hehe' a == b => true # Łańcuchy są naprawdę identyczne a.object_id == b.object_id => false # Mamy dwa różne obiekty do przechowywania tej samej zawartości
Symbole - bezpośrednie wartości
a = :test => :test b = :test => :test a.object_id == b.object_id => true # Mamy jedną wartość w pamięci i dwie zmienne, które na nią wskazują
To samo dotyczy true, false i nil
a = true b = true a.object_id == b.object_id => true a = false b = false a.object_id == b.object_id => true a = nil b = nil a.object_id == b.object_id => true
Ruby rezerwuje pewne identyfikatory obiektów dla tych obiektów bezpośrednich wartości, ponieważ każda zmienna, która ma przypisaną bezpośrednią wartość - wskazuje na to samo miejsce w pamięci. Sprawdźmy:
true.object_id => 20 false.object_id => 0 nil.object_id => 4 a = true => true b = false => false c = nil => nil a.object_id => 20 b.object_id => 0 c.object_id => 4
A lepiej - napiszmy rspec:
require 'rspec'
describe "Bezpośrednie wartości i referencje w Ruby" do
it "demonstruje bezpośrednie wartości vs referencje" do
# Bezpośrednie wartości
a = 5
b = a
expect(a.object_id).to eq(b.object_id)
# Referencja
a = [1, 2, 3]
b = a
expect(a.object_id).to eq(b.object_id)
end
it "demonstruje object_id dla bezpośrednich wartości" do
# True
a = true
b = true
expect(a.object_id).to eq(b.object_id)
# False
a = false
b = false
expect(a.object_id).to eq(b.object_id)
# Nil
a = nil
b = nil
expect(a.object_id).to eq(b.object_id)
end
it "demonstruje object_id dla symboli" do
a = :test
b = :test
expect(a.object_id).to eq(b.object_id)
end
it "demonstruje object_id dla zamrożonych literałów" do
a = 'test'.freeze
b = 'test'.freeze
expect(a.object_id).to eq(b.object_id)
end
it "demonstruje statyczny object_id dla true, false, nil" do
expect(true.object_id).to eq(20)
expect(false.object_id).to eq(0)
expect(nil.object_id).to eq(4)
end
end
Finished in 0.01952 seconds (files took 0.27884 seconds to load) 5 examples, 0 failures
Mam nadzieję, że ta informacja pomoże komuś lepiej zrozumieć immediate value oraz reference w Ruby.
Ten post nie ma jeszcze żadnych dodatków od autora.