В чем разница между
- параметр, переданный по ссылке
- параметр передается по значению?
Не могли бы вы привести несколько примеров, пожалуйста?
language-agnostic
pass-by-reference
pass-by-value
Deduplicator
источник
источник
Ответы:
Во-первых, различие между передачей по стоимости и передачей по ссылке, как это определено в теории CS, теперь устарело, поскольку техника, первоначально определенная как «передача по ссылке», с тех пор перестала пользоваться популярностью и в настоящее время редко используется. 1
Более новые языки 2, как правило, используют другую (но схожую) пару методов для достижения тех же результатов (см. Ниже), что является основным источником путаницы.
Вторым источником путаницы является тот факт, что в «передаче по ссылке» «ссылка» имеет более узкое значение, чем общий термин «ссылка» (потому что фраза предшествует этому).
Теперь, подлинное определение:
Когда параметр передается по ссылке , вызывающая сторона и вызываемая сторона используют одну и ту же переменную для параметра. Если вызываемый объект изменяет переменную параметра, эффект виден для переменной вызывающего.
Когда параметр передается по значению , вызывающая сторона и вызываемая сторона имеют две независимые переменные с одинаковым значением. Если вызываемый объект изменяет переменную параметра, эффект не будет виден вызывающему.
Что следует отметить в этом определении:
«Переменная» здесь означает саму переменную вызывающего (локальную или глобальную) - то есть, если я передам локальную переменную по ссылке и назначу ее, я изменю саму переменную вызывающего, а не, например, на то, на что она указывает, если это указатель ,
Значение «ссылка» в «передать по ссылке» . Разница с общим термином «ссылка» заключается в том, что эта «ссылка» является временной и неявной. В сущности, вызываемый объект получает «переменную», которая как-то «совпадает» с исходной. То, как конкретно достигается этот эффект, не имеет значения (например, язык может также раскрывать некоторые детали реализации - адреса, указатели, разыменование - это все не имеет значения; если это чистый эффект, то это передача по ссылке).
Теперь в современных языках переменные имеют тенденцию быть «ссылочными типами» (другая концепция, изобретенная позже, чем «передача по ссылке» и вдохновленная ими), то есть фактические данные объекта хранятся где-то отдельно (обычно в куче), и только «ссылки» на него когда-либо хранятся в переменных и передаются как параметры. 3
Передача такой ссылки подпадает под передачу по значению, поскольку технически значением переменной является сама ссылка, а не упомянутый объект. Тем не менее, общий эффект на программу может быть таким же, как передача по значению или передача по ссылке:
Как вы можете видеть, эта пара техник почти такая же, как в определении, только с уровнем косвенности: просто замените «переменную» на «объект ссылки».
Для них нет согласованного имени, что приводит к искаженным объяснениям, таким как «вызов по значению, где значение является ссылкой». В 1975 году Барбара Лисков предложила термин « обмен вызовами по объектам » (или иногда просто «обмен вызовами по обмену»), хотя он так и не получил широкого распространения. Более того, ни одна из этих фраз не проводит параллели с оригинальной парой. Неудивительно, что старые термины в конечном итоге использовались в отсутствие чего-то лучшего, что приводило к путанице. 4
ПРИМЕЧАНИЕ : в течение длительного времени этот ответ говорил:
Это в основном правильно, за исключением более узкого значения «ссылка» - оно является как временным, так и неявным (это не обязательно, но быть явным и / или постоянным - это дополнительные функции, а не часть семантики передачи по ссылке) , как объяснено выше). Более близкая аналогия - дать вам копию документа и пригласить вас поработать над оригиналом.
1 Если вы не программируете на Fortran или Visual Basic, это не стандартное поведение, и в большинстве современных языков использование истинного вызова по ссылке даже невозможно.
2 Изрядное количество старших тоже поддерживают это
3 В нескольких современных языках все типы являются ссылочными типами. Этот подход был впервые введен языком CLU в 1975 году и с тех пор был принят многими другими языками, включая Python и Ruby. И многие другие языки используют гибридный подход, где некоторые типы являются «типами значений», а другие - «ссылочными типами» - среди них C #, Java и JavaScript.
4 Нет ничего плохого в переработке подходящего старого термина как такового, но нужно как-то прояснить, какой смысл используется каждый раз. Не делать это именно то, что продолжает вызывать замешательство.
источник
Это способ передачи аргументов в функции. Передача по ссылке означает, что параметр вызываемых функций будет таким же, как переданный аргумент вызывающего (не значение, а идентификатор - сама переменная). Передача по значению означает, что параметр вызываемых функций будет копией переданного аргумента вызывающей стороны. Значение будет таким же, но идентичность - переменная - отличается. Таким образом, изменения параметра, выполняемого вызываемой функцией, в одном случае изменяют передаваемый аргумент, а в другом случае просто изменяют значение параметра в вызываемой функции (которая является только копией). В быстрой спешке:
ref
используемое в вызывающей и вызываемой функции). Джон Скит также имеет хорошее объяснение этого здесь .коды
Так как мой язык - C ++, я буду использовать это здесь
И пример на Java не повредит:
Википедия
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_value
http://en.wikipedia.org/wiki/Pass_by_reference#Call_by_reference
Этот парень в значительной степени прибивает это:
http://javadude.com/articles/passbyvalue.htm
источник
Многие ответы здесь (и, в частности, ответ с наибольшим количеством голосов) фактически неверны, так как они неправильно понимают, что на самом деле означает «вызов по ссылке». Вот моя попытка исправить ситуацию.
TL; DR
Проще говоря:
В метафорических терминах:
Что не означает «звонок по значению» и «звонок по ссылке»
Обратите внимание, что обе эти концепции полностью независимы и ортогональны от концепции ссылочных типов (которая в Java - это все типы, которые являются подтипами
Object
, а в C # - всеclass
типы) или от концепции типов указателей, подобных C (которые семантически эквивалентны). на «ссылочные типы» Java, просто с другим синтаксисом).Понятие ссылочного типа соответствует URL: оно само является частью информации и является ссылкой ( указатель , если хотите) на другую информацию. У вас может быть много копий URL в разных местах, и они не меняют сайт, на который они все ссылаются; если сайт обновляется, то каждая копия URL будет по-прежнему приводить к обновленной информации. И наоборот, изменение URL в любом месте не повлияет на любую другую письменную копию URL.
Обратите внимание , что C ++ есть понятие «ссылка» (например
int&
) , что является не как Java и C # 's „ссылочных типов“, но это как „вызов по ссылке“. «Ссылочные типы» в Java и C # и все типы в Python похожи на то, что в C и C ++ называют «типами указателей» (напримерint*
).Хорошо, вот более длинное и более формальное объяснение.
терминология
Для начала я хочу выделить некоторые важные термины, чтобы уточнить мой ответ и убедиться, что мы все ссылаемся на одни и те же идеи, когда используем слова. (На практике я полагаю, что подавляющее большинство путаницы по таким темам связано с использованием слов таким образом, чтобы не полностью передать смысл, который предполагался.)
Для начала вот пример на некотором C-подобном языке объявления функции:
И вот пример вызова этой функции:
Используя этот пример, я хочу определить некоторые важные биты терминологии:
foo
является функцией, объявленной в строке 1 (Java настаивает на создании всех методов функций, но концепция одинакова без потери общности; в C и C ++ проводится различие между объявлением и определением, которое я не буду здесь рассматривать)param
является формальным параметр , чтобыfoo
, также объявлен в строке-arg
является переменной , конкретно локальной переменной функцииbar
, объявленной и инициализирован в строке 2arg
также является аргументом для конкретного вызова вfoo
строке 3Здесь следует выделить два очень важных набора понятий. Первый - это значение в зависимости от переменной :
bar
выше функции после строкиint arg = 1;
выражениеarg
имеет значение1
.final
или C #readonly
) или может быть неизменной (например, с использованием C ++const
).Другая важная пара понятий, которые следует различать, это параметр против аргумента :
Звонок по значению
При вызове по значению формальные параметры функции - это переменные, которые заново создаются для вызова функции и инициализируются значениями их аргументов.
Это работает точно так же, как любые другие виды переменных инициализируются значениями. Например:
Здесь
arg
иanother_variable
есть полностью независимые переменные - их значения могут меняться независимо друг от друга. Тем не менее, в точке, гдеanother_variable
объявлено, он инициализируется для хранения того же значения, котороеarg
содержит - что есть1
.Поскольку они являются независимыми переменными, изменения
another_variable
не влияют наarg
:Это точно так же, как отношения между
arg
иparam
в нашем примере выше, который я повторю здесь для симметрии:Это точно так, как если бы мы написали код таким образом:
То есть определяющей характеристикой того, что означает вызов по значению, является то, что вызываемый объект (
foo
в данном случае) получает значения в качестве аргументов, но имеет свои собственные отдельные переменные для этих значений из переменных вызывающего (bar
в данном случае).Возвращаясь к моей метафоре выше, если я
bar
и тыfoo
, когда я звоню тебе, я вручаю вам кусок бумаги с значением , написанным на ней. Вы называете этот листок бумагиparam
. Это значение является копией значения, которое я написал в своей записной книжке (мои локальные переменные) в переменной, которую я вызываюarg
.(Кроме того: в зависимости от аппаратного обеспечения и операционной системы существуют различные соглашения о вызовах о том, как вы вызываете одну функцию из другой. Соглашение о вызовах похоже на то, как мы решаем, записать ли я значение на листе своей бумаги и затем передам вам или если у вас есть лист бумаги, на котором я его пишу, или если я напишу его на стене перед нами обоими. Это тоже интересная тема, но далеко за рамками этого уже длинного ответа.)
Звоните по ссылке
При обращении по ссылке формальные параметры функции - это просто новые имена для тех же переменных, которые вызывающая сторона предоставляет в качестве аргументов.
Возвращаясь к нашему примеру выше, это эквивалентно:
Поскольку
param
это просто другое имя дляarg
- то есть они являются одной и той же переменной , измененияparam
отражаются вarg
. Это основной способ, которым вызов по ссылке отличается от вызова по значению.Очень немногие языки поддерживают вызов по ссылке, но C ++ может сделать это так:
В этом случае,
param
не только имеют такую же ценность , какarg
, на самом деле являетсяarg
(только под другим именем) , и поэтомуbar
можно заметить , чтоarg
было увеличено.Обратите внимание, что это не так, как работает сегодня любой из Java, JavaScript, C, Objective-C, Python или почти любой другой популярный язык. Это означает, что эти языки не называются по ссылке, они называются по значению.
Приложение: вызов по обмену объектами
Если то, что у вас есть, это вызов по значению , но фактическое значение является ссылочным типом или типом указателя , то само «значение» не очень интересно (например, в C это просто целое число, зависящее от платформы) - что интересно то, на что указывает это значение .
Если то, на что указывает этот ссылочный тип (то есть указатель), является изменчивым, то возможен интересный эффект: вы можете изменить значение, на которое указывает указатель, и вызывающая сторона может наблюдать изменения значения, на которое указывает указатель, даже если вызывающая сторона не может наблюдать меняется на сам указатель.
Снова заимствуя аналогию с URL, тот факт, что я дал вам копию URL для веб-сайта, не особенно интересен, если нас обоих волнует не веб-сайт, а веб-сайт. Тот факт, что вы перебираете свою копию URL-адреса, не влияет на мою копию URL-адреса, нас не волнует (и на самом деле, в таких языках, как Java и Python, «URL», или значение ссылочного типа, может не может быть изменен, может только указанная им вещь).
Барбара Лисков, когда она изобрела язык программирования CLU (который имел эту семантику), поняла, что существующие термины «вызов по значению» и «вызов по ссылке» не особенно полезны для описания семантики этого нового языка. Таким образом, она изобрела новый термин: вызов через разделение объектов .
При обсуждении языков, которые технически называются по значению, но в которых распространенными типами являются ссылочный тип или тип указателя (т. Е. Почти каждый современный императивный, объектно-ориентированный или мультипарадигмальный язык программирования), я нахожу, что его гораздо меньше смущает просто избегайте разговоров о звонке по значению или звонке по ссылке . Придерживайтесь вызова через общий доступ к объектам (или просто вызов по объекту ), и никто не будет смущен. :-)
источник
The first is value versus variable.
The other important pair of concepts to distinguish is parameter versus argument:
Прежде чем понимать 2 условия, вы ДОЛЖНЫ понять следующее. У каждого объекта есть 2 вещи, которые могут его выделить.
Так что если вы скажете
employee.name = "John"
знаю, что есть 2 вещи о
name
. Его значение , которое ,"John"
а также его расположение в памяти , которая некоторое шестнадцатеричное число , может быть , как это:0x7fd5d258dd00
.В зависимости от архитектуры языка или типа (класса, структуры и т. Д.) Вашего объекта, вы будете либо передавать,
"John"
либо0x7fd5d258dd00
Передача
"John"
называется передачей по значению. Передача0x7fd5d258dd00
называется передачей по ссылке. Любой, кто указывает на эту область памяти, будет иметь доступ к значению"John"
.Более подробно об этом я рекомендую вам прочитать о разыменовании указателя, а также о том, почему следует выбирать struct (тип значения) вместо класса (ссылочный тип)
источник
Вот пример:
источник
y
уже было установлено на 2 предыдущей строкой. Почему бы вернуться к 0?Самый простой способ получить это - файл Excel. Скажем, например, что у вас есть два числа, 5 и 2 в ячейках A1 и B1 соответственно, и вы хотите найти их сумму в третьей ячейке, скажем, A2. Вы можете сделать это двумя способами.
Либо, передав их значения в ячейку A2 , введя = 5 + 2 в эту ячейку. В этом случае, если значения ячеек A1 или B1 изменяются, сумма в A2 остается неизменной.
Или передавая «ссылки» ячеек A1 и B1 в ячейку A2 , набрав = A1 + B1 . В этом случае, если значения ячеек A1 или B1 изменяются, сумма в A2 также изменяется.
источник
При передаче по ref вы в основном передаете указатель на переменную. Передавая по значению, вы передаете копию переменной. При базовом использовании это обычно означает, что переданные по ref изменения в переменной будут рассматриваться как вызывающий метод, а переданные по значению они не будут.
источник
При передаче по значению отправляется КОПИЯ данных, хранящихся в указанной вами переменной, при передаче по ссылке отправляется прямая ссылка на саму переменную. Поэтому, если вы передадите переменную по ссылке, а затем измените переменную внутри блока, в который она была передана, исходная переменная будет изменена. Если вы просто передадите по значению, исходная переменная не сможет быть изменена блоком, в который вы ее передали, но вы получите копию того, что она содержала во время вызова.
источник
Передача по значению - функция копирует переменную и работает с копией (поэтому она ничего не меняет в исходной переменной)
Передача по ссылке - функция использует исходную переменную; если вы изменяете переменную в другой функции, она также изменяется и в исходной переменной.
Пример (скопируйте и используйте / попробуйте сами и посмотрите):
Держите это просто, выглядывает. Стены текста могут быть вредной привычкой.
источник
Основное различие между ними заключается в том, что переменные типа значения хранят значения, поэтому указание переменной типа значения в вызове метода передает копию значения этой переменной в метод. Переменные ссылочного типа хранят ссылки на объекты, поэтому указание переменной ссылочного типа в качестве аргумента передает методу копию фактической ссылки, которая ссылается на объект. Даже если сама ссылка передается по значению, метод может использовать полученную ссылку для взаимодействия с исходным объектом и, возможно, для его изменения. Аналогично, при возврате информации из метода через оператор return метод возвращает копию значения, хранящегося в переменной типа значения, или копию ссылки, хранящейся в переменной типа ссылки. Когда ссылка возвращается, вызывающий метод может использовать эту ссылку для взаимодействия с указанным объектом. Так,
В c # для передачи переменной по ссылке, чтобы вызываемый метод мог изменять переменные, C # предоставляет ключевые слова ref и out. Применение ключевого слова ref к объявлению параметра позволяет передавать переменную в метод по ссылке - вызываемый метод сможет изменять исходную переменную в вызывающей стороне. Ключевое слово ref используется для переменных, которые уже были инициализированы в вызывающем методе. Обычно, когда вызов метода содержит неинициализированную переменную в качестве аргумента, компилятор генерирует ошибку. Предшествующий параметр с ключевым словом out создает выходной параметр. Это указывает компилятору, что аргумент будет передан в вызываемый метод по ссылке и что вызываемый метод назначит значение исходной переменной в вызывающей программе. Если метод не присваивает значение выходному параметру на каждом возможном пути выполнения, компилятор генерирует ошибку. Это также препятствует тому, чтобы компилятор генерировал сообщение об ошибке для неинициализированной переменной, которая передается в качестве аргумента методу. Метод может возвратить вызывающей стороне только одно значение с помощью оператора return, но может вернуть много значений, указав несколько выходных (ref и / или out) параметров.
см. обсуждение c # и примеры здесь, текст ссылки
источник
Примеры:
const &
как правило, лучше. Вы не несете штраф за строительство и разрушение. Если ссылка не является константой, ваш интерфейс предполагает, что она изменит переданные данные.источник
Короче говоря, Passed by value - это то, ЧТО это и передается по ссылке, ГДЕ это.
Если ваше значение VAR1 = «Счастливый парень!», Вы увидите только «Счастливый парень!». Если VAR1 изменится на «Happy Gal!», Вы об этом не узнаете. Если он передается по ссылке, а VAR1 изменяется, вы это сделаете.
источник
Если вы не хотите изменять значение исходной переменной после ее передачи в функцию, функция должна быть построена с параметром « pass by value ».
Тогда функция будет иметь ТОЛЬКО значение, но не адрес переданной переменной. Без адреса переменной код внутри функции не может изменить значение переменной, как видно снаружи функции.
Но если вы хотите дать функции возможность изменять значение переменной, как видно снаружи, вам нужно использовать передачу по ссылке . Поскольку значение и адрес (ссылка) передаются и доступны внутри функции.
источник
передача по значению означает, как передать значение в функцию, используя аргументы. при передаче по значению мы копируем данные, хранящиеся в указанной переменной, и это происходит медленнее, чем передача по ссылке, поскольку данные копируются. Мы вносим изменения в скопированные данные, исходные данные не затрагиваются. При передаче по ссылке или по адресу мы отправляем прямую ссылку на саму переменную. или передав указатель на переменную. это быстрее, потому что меньше времени потребляется
источник
Вот пример, который демонстрирует различия между передачей по значению - значением указателя - ссылкой :
Метод «передачи по ссылке» имеет важное ограничение . Если параметр объявлен как переданный по ссылке (поэтому ему предшествует знак &), его соответствующий фактический параметр должен быть переменной .
Фактический параметр, ссылающийся на формальный параметр «передано по значению», может быть выражением в целом, поэтому допускается использование не только переменной, но также литерала или даже результата вызова функции.
Функция не может поместить значение в нечто иное, чем переменная. Он не может присвоить литералу новое значение или заставить выражение изменить его результат.
PS: Вы также можете проверить ответ Дилана Битти в текущей ветке, которая объясняет его простыми словами.
источник