@user.update_languages(params[:language][:language1],
params[:language][:language2],
params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------"
+ lang_errors.full_messages.inspect
if params[:user]
@user.state = params[:user][:state]
success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------"
+ lang_errors.full_messages.inspect
if lang_errors.full_messages.empty?
@user
Объект добавляет ошибки к lang_errors
переменной в update_lanugages
методе. когда я выполняю сохранение @user
объекта, я теряю ошибки, которые изначально были сохранены в lang_errors
переменной.
Хотя то, что я пытаюсь сделать, было бы скорее хаком (который, похоже, не работает). Я хотел бы понять, почему значения переменных вымываются. Я понимаю, что передача по ссылке, поэтому я хотел бы знать, как значение может храниться в этой переменной, не стираясь.
Ответы:
В традиционной терминологии Ruby строго передается по значению . Но это не совсем то, что вы спрашиваете здесь.
Ruby не имеет понятия чистого, не ссылочного значения, поэтому вы определенно не можете передать его методу. Переменные всегда являются ссылками на объекты. Чтобы получить объект, который не изменится из-под вас, вам нужно дублировать или клонировать переданный вами объект, таким образом давая объект, на который никто больше не ссылается. (Однако даже это не является пуленепробиваемым - оба стандартных метода клонирования делают поверхностное копирование, поэтому переменные экземпляра клона по-прежнему указывают на те же объекты, что и оригиналы. Если объекты, на которые ссылается ивар, видоизменяются, это будет по-прежнему отображаются в копии, поскольку ссылаются на те же объекты.)
источник
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
.Остальные ответчики все правы, но друг попросил меня объяснить ему это, и что на самом деле сводится к тому, как Ruby обрабатывает переменные, поэтому я подумал, что поделюсь некоторыми простыми картинками / объяснениями, которые я написал для него (извинения за длину и, вероятно, некоторое упрощение)
В1: Что происходит, когда вы назначаете новую переменную
str
значению'foo'
?A: Создана вызываемая метка,
str
которая указывает на объект'foo'
, который для состояния этого интерпретатора Ruby оказывается в ячейке памяти2000
.Q2: Что происходит, когда вы назначаете существующую переменную
str
новому объекту с помощью=
?A: Метка
str
теперь указывает на другой объект.Q3: что происходит, когда вы назначаете новую переменную
=
вstr
?A: Создана новая метка с именем,
str2
которая указывает на тот же объект, что иstr
.Q4: что произойдет, если объект, на который ссылается
str
иstr2
будет изменен?A: Обе метки по-прежнему указывают на один и тот же объект, но сам объект мутировал (его содержимое изменилось на что-то другое).
Как это связано с первоначальным вопросом?
В основном это то же самое, что происходит в Q3 / Q4; метод получает свою собственную частную копию переменной / label (
str2
), которая передается ему (str
). Он не может изменить объект, на которыйstr
указывает метка , но он может изменить содержимое объекта, на который они оба ссылаются, чтобы содержать else:источник
Ruby использует «передачу по ссылке на объект»
(Используя терминологию Python.)
Сказать, что в Ruby используется «передача по значению» или «передача по ссылке», на самом деле недостаточно, чтобы быть полезным. Я думаю, что, как большинство людей знают это в наши дни, эта терминология («значение» против «ссылка») происходит из C ++.
В C ++ «передача по значению» означает, что функция получает копию переменной, и любые изменения в копии не изменяют оригинал. Это верно и для объектов. Если вы передаете переменную объекта по значению, тогда весь объект (включая все его члены) копируется, и любые изменения в элементах не изменяют эти элементы в исходном объекте. (Другое дело, если вы передаете указатель по значению, но в Ruby все равно нет указателей, AFAIK.)
Вывод:
В C ++ «передача по ссылке» означает, что функция получает доступ к исходной переменной. Он может назначить целое новое литеральное целое число, и тогда исходная переменная также будет иметь это значение.
Вывод:
Ruby использует передачу по значению (в смысле C ++), если аргумент не является объектом. Но в Ruby все является объектом, поэтому в Ruby нет смысла передавать по значению в C ++.
В Ruby используется «передача по ссылке на объект» (для использования терминологии Python):
Поэтому Ruby не использует «передачу по ссылке» в смысле C ++. Если это так, то присвоение нового объекта переменной внутри функции приведет к тому, что старый объект будет забыт после возврата функции.
Вывод:
Вот почему в Ruby, если вы хотите изменить объект внутри функции, но забыть об этих изменениях при возврате функции, вы должны явно сделать копию объекта, прежде чем вносить временные изменения в копию.
источник
def ch(str) str.reverse! end; str="abc"; ch(str); puts str #=> "cba"
def foo(bar) bar = 'reference' end; baz = 'value'; foo(baz); puts "Ruby is pass-by-#{baz}"
. Это печатает "Рубин передается по значению". Но переменная внутриfoo
переназначена. Еслиbar
бы был массив, переназначение не произойдетbaz
. Зачем?Ruby передается по значению. Всегда. Без исключений. Нет, если Никаких "но.
Вот простая программа, которая демонстрирует этот факт:
источник
Ruby в строгом смысле передается по значению, НО значения являются ссылками.
Это можно назвать « передачей по значению ». Эта статья имеет лучшее объяснение, которое я читал: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Передача-ссылка-значение может быть кратко объяснена следующим образом:
Получающееся поведение фактически является комбинацией классических определений передачи по ссылке и передачи по значению.
источник
Уже есть несколько хороших ответов, но я хочу опубликовать определение пары авторитетов по этому вопросу, но также надеюсь, что кто-то может объяснить, что сказали авторитеты Матц (создатель Ruby) и Дэвид Фланаган в своей превосходной книге О'Рейли, Язык программирования Ruby .
Это все имеет смысл для меня до последнего абзаца и особенно до последнего предложения. Это в лучшем случае вводит в заблуждение, а в худшем - смешивает. Каким образом изменения в этой переданной по значению ссылке могут изменить базовый объект?
источник
Руби это передача по ссылке. Всегда. Без исключений. Нет, если Никаких "но.
Вот простая программа, которая демонстрирует этот факт:
источник
bar
методе. Вы просто модифицируете объект, на который указывает ссылка , но не саму ссылку. Единственный способ изменить ссылки в Ruby - по назначению. Вы не можете изменять ссылки, вызывая методы в Ruby, потому что методы можно вызывать только для объектов, а ссылки не являются объектами в Ruby. Ваш пример кода демонстрирует, что Ruby имеет общее изменяемое состояние (что здесь не обсуждается), однако он ничего не делает для того, чтобы осветить различие между передачей по значению и передачей по ссылке.Параметры являются копией оригинальной ссылки. Таким образом, вы можете изменить значения, но не можете изменить исходную ссылку.
источник
Попробуй это:--
идентификатор a содержит object_id 3 для объекта значения 1, а идентификатор b содержит object_id 5 для объекта значения 2.
Теперь сделайте это:
Теперь, a и b оба содержат один и тот же object_id 5, который ссылается на объект значения 2. Таким образом, переменная Ruby содержит object_ids для ссылки на объекты значения.
Выполнение следующих действий также дает ошибку:
но это не даст ошибки:
Здесь идентификатор возвращает значение объекта 11, чей идентификатор объекта равен 23, то есть object_id 23 находится на идентификаторе a. Теперь мы видим пример с использованием метода.
Аргумент в foo присваивается с возвращаемым значением х. Это ясно показывает, что аргумент передается значением 11, а значение 11 само по себе является объектом с уникальным идентификатором объекта 23.
Теперь посмотрите также:
Здесь идентификатор arg сначала содержит object_id 23 для ссылки 11, а после внутреннего присваивания со значением объекта 12 он содержит object_id 25. Но он не меняет значение, на которое ссылается идентификатор x, используемый в вызывающем методе.
Следовательно, Ruby передается по значению, а переменные Ruby не содержат значений, но содержат ссылку на объект значения.
источник
Руби интерпретируется. Переменные - это ссылки на данные, но не сами данные. Это облегчает использование одной и той же переменной для данных разных типов.
Присвоение lhs = rhs затем копирует ссылку на rhs, а не данные. Это отличается в других языках, таких как C, где присваивание копирует данные в lhs из rhs.
Таким образом, для вызова функции переданная переменная, скажем, x, действительно копируется в локальную переменную в функции, но x является ссылкой. Затем будет две копии ссылки, обе ссылаются на одни и те же данные. Один будет в звонящем, другой в функции.
Назначение в функции затем скопирует новую ссылку на версию функции x. После этого версия вызывающего абонента x остается неизменной. Это все еще ссылка на исходные данные.
Напротив, использование метода .replace для x приведет к тому, что ruby сделает копию данных. Если замена используется перед любыми новыми назначениями, тогда вызывающая сторона также увидит изменение данных в своей версии.
Точно так же, пока исходная ссылка находится в такте для переданной переменной, переменные экземпляра будут такими же, как видит вызывающая сторона. В рамках объекта переменные экземпляра всегда имеют самые современные ссылочные значения, независимо от того, предоставляются ли они вызывающей стороной или задаются в функции, которой был передан класс.
'Вызов по значению' или 'Вызов по ссылке' здесь запутан из-за путаницы над '=' В скомпилированных языках '=' является копией данных. Здесь на этом интерпретируемом языке '=' является справочной копией. В этом примере передается ссылка, за которой следует ссылочная копия, хотя '=', которая перекрывает оригинал, переданный в ссылке, а затем люди говорят об этом, как если бы '=' была копией данных.
Чтобы соответствовать определениям, мы должны придерживаться «.replace», так как это копия данных. С точки зрения «.replace» мы видим, что это действительно передача по ссылке. Кроме того, если мы пройдем через отладчик, мы увидим, что ссылки передаются, поскольку переменные являются ссылками.
Однако если мы должны сохранить '=' в качестве системы отсчета, тогда мы действительно увидим переданные данные вплоть до назначения, а затем мы больше не увидим их после назначения, пока данные вызывающей стороны остаются неизменными. На поведенческом уровне это передается по значению, пока мы не считаем переданное значение составным - поскольку мы не сможем сохранить его часть при изменении другой части в одном назначении (как это назначение изменяет ссылку и оригинал выходит за рамки видимости). Также будет бородавка, в этом случае переменные в объектах будут ссылками, как и все переменные. Следовательно, мы будем вынуждены говорить о передаче «ссылки по значению» и должны использовать связанные выражения.
источник
Следует отметить, что вам даже не нужно использовать метод «заменить», чтобы изменить исходное значение. Если вы назначите одно из значений хеш-функции для хэша, вы измените исходное значение.
источник
Любые обновления в том же объекте не будут ссылаться на новую память, поскольку она все еще находится в той же памяти. Вот несколько примеров:
источник
Да, но ....
Ruby передает ссылку на объект, и поскольку все в ruby является объектом, вы можете сказать, что он передается по ссылке.
Я не согласен с сообщениями здесь, утверждающими, что это передача по значению, которая кажется мне педантичной, символической игрой.
Однако, по сути, он «скрывает» поведение, потому что большинство операций ruby предоставляет «из коробки» - например, строковые операции создают копию объекта:
Это означает, что большую часть времени исходный объект остается неизменным, создавая впечатление, что ruby является «передачей по значению».
Конечно, при разработке ваших собственных классов понимание деталей этого поведения важно как для функционального поведения, эффективности памяти и производительности.
источник