Наконец-то я нашел способ понять переменные и объекты, передачу по значению и передачу по ссылке. Это по-прежнему сложная тема, но я думаю, что есть способ проиллюстрировать концепцию с помощью IRB и некоторых общих объектов.
Начнем с двух строк
a = 'test' b = 'test' a.object_id != b.object_id
Когда две переменные содержат одну и ту же строку «значение», как в приведенном выше примере, оба объекта имеют разные идентификаторы объекта. Это означает, что это разные объекты. Таким образом, можно сказать, что строка "test"
существует в памяти два раза.
a = :test b = :test a.object_id == b.object_id
С другой стороны, когда символ присваивается двум переменным, обе переменные указывают на один и тот же объект. Это означает, что символ :test
существует в памяти только один раз. Независимо от того, где :test
используется в программе, куда он передается или откуда на него делается ссылка, он всегда будет одним и тем же объектом.
a = true b = true a.object_id == b.object_id
Как насчет логического значения? И снова тот же объект. Логическое значение true
(или false
) существует в памяти только один раз, когда когда-либо переменной присваивается логическое значение, независимо от того, как это произошло, оно будет ссылаться на один и тот же объект в памяти.
Что меня поразило, так это объект nil
. Когда переменной присваивается значение nil
, она всегда будет указывать на один и тот же адрес в памяти.
a = nil b = nil a.object_id == b.object_id
Nil всегда имеет один и тот же идентификатор объекта
Я обнаружил, что идентификаторы объектов nil
, true
, false
и целые числа всегда имеют одно и то же значение, независимо от системы.
nil.object_id # 8 5.object_id # 11 true.object_id # 20
Это показывает мне, что Ruby резервирует определенные идентификаторы объектов для этих объектов, потому что каждая переменная, назначенная одному из этих объектов, всегда будет указывать на один и тот же объект, хранящийся в памяти.
Неизменяемые объекты существуют только один раз в памяти
Моя упрощенная реализация заключалась в том, что когда объект в Ruby неизменяем, он также существует только один раз в памяти. Это означает, что все переменные, присвоенные этому объекту, всегда будут указывать на одно и то же адресное пространство.
a = 5 b = 5 a.object_id == b.object_id
Целые числа являются неизменяемыми объектами, поэтому переменные указывают на один и тот же объект.
a.to_s.object_id != b.to_s_object_id
Превращение объектов в строки переназначает переменные бота новому строковому объекту. Оба строковых объекта содержат значение "5"
, но являются разными объектами и находятся в разных местах памяти. Поэтому идентификаторы объектов разные.
Передача по значению и передача по ссылке
def shoveling(variable) variable << 33 end number = 5 array = [5] string = '5' p shoveling(number) # 42949672960 p shoveling(array) # [5, 33] p shoveling(string) # '5!' p number # 5 p array # [5, 33] p string # '5!'
Это надуманный пример, но он показывает, что один и тот же метод name<<
реализуется по-разному для разных классов объектов.
- В случае целого числа
5
передаваемый объект не изменяется, потому что целые числа неизменяемы, аInteger#<<
не может изменяться. - Массив с другой стороны видоизменен, и поэтому объект, на который указывает
array
, изменяется внутри и вне метода. - То же самое касается объекта переменной
string
. Он мутирует как внутри, так и вне метода.
В чем преимущество передачи по значению или по ссылке?
Это не имеет значения! Для меня ruby всегда передается по ссылке, потому что целое число 5
существует в памяти только один раз. Это означает, что переменная number
и переменная variable
будут указывать на один и тот же адрес в памяти при вызове метода.
Когда метод Integer#<<
затем вызывается в следующей строке, объект не изменяется, а возвращается новый целочисленный объект, который возвращается методом.
Для меня большим прорывом стало осознание того, что все, что мне нужно сделать, это сначала посмотреть на объект и убедиться, что он неизменен.
И если объект изменчив, то посмотреть на методы и посмотреть, мутируют ли они переданные объекты.
Если объект неизменяем и если не используются методы мутации, нежелательных побочных эффектов быть не может!