Как зайти в Даркнет?!
25th January, 01:11
5
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
893
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
912
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6085
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4350
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4395
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Передать по ссылке или передать по значению?
При изучении нового языка программирования одним из возможных препятствий, с которыми вы можете столкнуться, является вопрос о том, является ли язык по умолчанию pass-by-value или pass-by-reference .
Итак, вот мой вопрос ко всем вам, на вашем любимом языке, как это на самом деле делается? И каковы же возможные подводные камни ?
Ваш любимый язык может, конечно , быть всем , с чем вы когда-либо играли: популярным , непонятным , эзотерическим, новым, старым ...
Вот мой собственный вклад для языка программирования Java .
сначала немного кода:
public void swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
вызов этого метода приведет к этому:
int pi = 3;
int everything = 42;
swap(pi, everything);
System.out.println("pi: " + pi);
System.out.println("everything: " + everything);
"Output:
pi: 3
everything: 42"
даже использование объектов 'real' покажет аналогичный результат:
public class MyObj {
private String msg;
private int number;
//getters and setters
public String getMsg() {
return this.msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getNumber() {
return this.number;
}
public void setNumber(int number) {
this.number = number;
}
//constructor
public MyObj(String msg, int number) {
setMsg(msg);
setNumber(number);
}
}
public static void swap(MyObj x, MyObj y)
{
MyObj tmp = x;
x = y;
y = tmp;
}
public static void main(String args[]) {
MyObj x = new MyObj("Hello world", 1);
MyObj y = new MyObj("Goodbye Cruel World", -1);
swap(x, y);
System.out.println(x.getMsg() + " -- "+ x.getNumber());
System.out.println(y.getMsg() + " -- "+ y.getNumber());
}
"Output:
Hello world -- 1
Goodbye Cruel World -- -1"
таким образом , очевидно, что Java передает свои параметры по значению, так как значение для pi и все остальное и объекты MyObj не меняются местами. имейте в виду, что "by value"-это единственный способ в java передать параметры в метод. (например, такой язык, как c++, позволяет разработчику передавать параметр по ссылке, используя ' & ' после типа параметра)
теперь самая сложная часть , или, по крайней мере, та часть, которая будет смущать большинство новых разработчиков java: (заимствовано из javaworld )
Автор оригинала: Тони Синтес
public void tricky(Point arg1, Point arg2)
{
arg1.x = 100;
arg1.y = 100;
Point temp = arg1;
arg1 = arg2;
arg2 = temp;
}
public static void main(String [] args)
{
Point pnt1 = new Point(0,0);
Point pnt2 = new Point(0,0);
System.out.println("X: " + pnt1.x + " Y: " +pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
System.out.println(" ");
tricky(pnt1,pnt2);
System.out.println("X: " + pnt1.x + " Y:" + pnt1.y);
System.out.println("X: " + pnt2.x + " Y: " +pnt2.y);
}
"Output
X: 0 Y: 0
X: 0 Y: 0
X: 100 Y: 100
X: 0 Y: 0"
tricky успешно изменяет значение pnt1! Это означало бы, что объекты передаются по ссылке, но это не так! Правильное утверждение было бы: ссылки на объект передаются по значению.
еще от Тони Синтеса:
Этот метод успешно изменяет значение pnt1, даже если оно равно передается по значению; тем не менее, своп pnt1 и pnt2 терпят неудачу! Это главное источник путаницы. В main() метод, pnt1 и pnt2-это не более того чем ссылки на объекты. Когда вы проходите мимо pnt1 и pnt2 к методу tricky(), Java передает ссылки по значению как и любой другой параметр. Этот означает ссылки, переданные на метод на самом деле являются копиями оригинальные ссылки. Рисунок 1 ниже показывает две ссылки, указывающие на тот же самый объект после Java проходит объект для метода.
(источник: javaworld.com )
Вывод или длинная история короче:
- Java передает его параметры по значению
- "by value" -это единственный способ в java, чтобы передать параметр в метод
- использование методов из объекта , заданного в качестве параметра, изменит объект, поскольку ссылки указывают на исходные объекты. (если этот метод сам изменяет некоторые значения)
полезные ссылки:
- http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
- http://www.ibm.com/developerworks/java/library/j-passbyval/
- http://www.ibm.com/developerworks/library/j-praxis/pr1.html
- http://javadude.com/articles/passbyvalue.htm
Вот еще одна статья для языка программирования c#
c# передает свои аргументы по значению (по умолчанию)
private void swap(string a, string b) {
string tmp = a;
a = b;
b = tmp;
}
вызов этой версии swap таким образом не будет иметь никакого результата:
string x = "foo";
string y = "bar";
swap(x, y);
"output:
x: foo
y: bar"
однако в отличие от java c# дает разработчику возможность передавать параметры по ссылке , это делается с помощью ключевого слова 'ref' перед типом параметра:
private void swap(ref string a, ref string b) {
string tmp = a;
a = b;
b = tmp;
}
этот своп изменит значение указанного параметра:
string x = "foo";
string y = "bar";
swap(x, y);
"output:
x: bar
y: foo"
c# также имеет ключевое слово out, и разница между ref и out очень тонкая. от msdn:
Вызывающий метод, который принимает параметр out не требуется для того, чтобы присвоить переменной, переданной как параметры до вызова; однако вызываемый абонент обязан: присвоить параметру out до этого возвращающийся.
и
В отличие от параметров ссылок считается первоначально назначенным вызываемый. Как таковой, вызываемый абонент не является требуется назначить параметр ref перед использованием. Параметр ref передаются как в а, так и из а метод.
небольшой подводный камень, как и в java, заключается в том, что объекты, переданные по значению, все еще могут быть изменены с помощью их внутренних методов
заключение :
- c# передает свои параметры, по умолчанию, по значению
- но при необходимости параметры также могут быть переданы по ссылке с помощью ключевого слова ref
- внутренние методы из параметра, передаваемого по значению, изменят объект (если этот метод сам изменяет некоторые значения)
полезные ссылки:
- http://msdn.microsoft.com/en-us/vcsharp/aa336814.aspx
- http://www.c-sharpcorner.com/UploadFile/saragana/Willswapwork11162005012542AM/Willswapwork.aspx
- http://en.csharp-online.net/Value_vs_Reference
Python использует pass-by-value, но так как все такие значения являются ссылками на объекты, то чистый эффект является чем-то сродни pass-by-reference. Однако программисты Python больше думают о том, является ли тип объекта изменяемым или неизменяемым . Изменяемые объекты могут быть изменены на месте (например, словари, списки, пользовательские объекты), в то время как неизменяемые объекты не могут быть изменены (например, целые числа, строки, кортежи).
В следующем примере показана функция, которой передаются два аргумента, неизменяемая строка и изменяемый список.
>>> def do_something(a, b):
... a = "Red"
... b.append("Blue")
...
>>> a = "Yellow"
>>> b = ["Black", "Burgundy"]
>>> do_something(a, b)
>>> print a, b
Yellow ['Black', 'Burgundy', 'Blue']
Строка a = "Red" просто создает локальное имя a для строкового значения "Red" и не влияет на передаваемый аргумент (который теперь скрыт, так как a должен ссылаться на локальное имя с этого момента). Присваивание не является операцией на месте, независимо от того, является ли аргумент изменяемым или неизменяемым.
Параметр b является ссылкой на изменяемый объект списка, а метод .append() выполняет расширение списка на месте, добавляя новое строковое значение "Blue" .
(Поскольку строковые объекты являются неизменяемыми, у них нет никаких методов, поддерживающих модификации на месте.)
Как только функция возвращается, повторное назначение a не имеет никакого эффекта, в то время как расширение b ясно показывает семантику вызова стиля pass-by-reference.
Как уже упоминалось ранее, даже если аргумент для a является изменяемым типом, повторное присвоение внутри функции не является операцией на месте, и поэтому не будет никакого изменения значения переданного аргумента:
>>> a = ["Purple", "Violet"]
>>> do_something(a, b)
>>> print a, b
['Purple', 'Violet'] ['Black', 'Burgundy', 'Blue', 'Blue']
Если вы не хотите, чтобы ваш список был изменен вызываемой функцией, вы бы вместо этого использовали неизменяемый тип кортежа (определяемый скобками в литеральной форме, а не квадратными скобками), который не поддерживает метод in-place .append() :
>>> a = "Yellow"
>>> b = ("Black", "Burgundy")
>>> do_something(a, b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in do_something
AttributeError: 'tuple' object has no attribute 'append'
Поскольку я еще не видел ответа на Perl, я решил написать его.
Под капотом Perl эффективно работает как pass-by-reference. Переменные в качестве аргументов вызова функции передаются ссылочно, константы-как значения, доступные только для чтения, а результаты выражений-как временные значения. Обычные идиомы для построения списков аргументов путем назначения списка от @_ или от shift имеют тенденцию скрывать это от пользователя, создавая видимость pass-by-value:
sub incr {
my ( $x ) = @_;
$x++;
}
my $value = 1;
incr($value);
say "Value is now $value";
Это выведет Value is now 1 , поскольку $x++ увеличило лексическую переменную, объявленную в функции incr() , а не переданную переменную. Этот стиль pass-by-value обычно является тем, что требуется большую часть времени, поскольку функции, изменяющие свои аргументы, редко встречаются в Perl, и этого стиля следует избегать.
Однако, если по какой-то причине это поведение особенно желательно, оно может быть достигнуто путем работы непосредственно с элементами массива @_ , поскольку они будут псевдонимами для переменных, передаваемых в функцию.
sub incr {
$_[0]++;
}
my $value = 1;
incr($value);
say "Value is now $value";
На этот раз он будет печатать Value is now 2 , потому что выражение $_[0]++ увеличило фактическую переменную $value . Это работает так, что под капотом @_ не является реальным массивом, как большинство других массивов (например, получаемых с помощью my @array), но вместо этого его элементы строятся непосредственно из аргументов, передаваемых вызову функции. Это позволяет построить семантику pass-by-reference, если это потребуется. Аргументы вызова функции, которые являются простыми переменными, вставляются as-is в этот массив, а константы или результаты более сложных выражений вставляются как временные значения, доступные только для чтения.
Однако на практике это делается крайне редко, поскольку Perl поддерживает ссылочные значения, то есть значения, ссылающиеся на другие переменные. Обычно гораздо проще построить функцию, которая имеет очевидный побочный эффект на переменную, передавая ссылку на эту переменную. Это явное указание читателю на сайте вызовов, что семантика pass-by-reference действует.
sub incr_ref {
my ( $ref ) = @_;
$$ref++;
}
my $value = 1;
incr(\$value);
say "Value is now $value";
Здесь оператор \ дает ссылку во многом таким же образом, как и оператор & адреса в C.
Здесь есть хорошее объяснение .NET.
Многие люди удивляются, что ссылочные объекты на самом деле передаются по значению (как в C#, так и в Java). Это копия адреса стека. Это предотвращает изменение метода в том месте, куда фактически указывает объект, но все же позволяет методу изменять значения объекта. В C# можно передавать ссылку по ссылке, что означает, что вы можете изменить, куда указывает фактический объект.
Не забудьте также пройти по имени , и передавать по значению-результату .
Pass by value-результат аналогичен pass by value, с добавленным аспектом, что значение устанавливается в исходной переменной, которая была передана в качестве параметра. Он может в некоторой степени избежать вмешательства в глобальные переменные. Это, по-видимому, лучше в секционированной памяти, где передача по ссылке может вызвать ошибку страницы ( ссылка ).
Передача по имени означает, что значения вычисляются только тогда, когда они фактически используются, а не в начале процедуры. Алгол использовал pass-by-name, но интересный побочный эффект заключается в том, что очень сложно написать процедуру подкачки ( Reference ). Кроме того, выражение, переданное по имени, повторно вычисляется при каждом обращении к нему, что также может иметь побочные эффекты.
Все, что вы говорите как pass-by-value или pass-by-reference, должно быть согласовано в разных языках. Наиболее распространенное и последовательное определение, используемое в разных языках, заключается в том, что с помощью pass-by-reference можно передать переменную функции "normally" (т. е. без явного указания адреса или чего-либо подобного), и функция может назначить (не изменять содержимое) параметр внутри функции, и это будет иметь тот же эффект, что и назначение переменной в вызывающей области.
С этой точки зрения языки сгруппированы следующим образом; каждая группа имеет одну и ту же проходящую семантику. Если вы считаете, что два языка не должны быть помещены в одну группу, я призываю вас привести пример, который отличает их друг от друга.
Подавляющее большинство языков в том числе C , Java , Python , Ruby , JavaScript , Scheme, OCaml, Standard ML, Go, Objective-C, Smalltalk и др. есть все pass-by-value только . Передача значения указателя (некоторые языки называют его a "reference") не считается передачей по ссылке; нас интересует только передаваемая вещь, указатель, а не то, на что он указывает.
Такие языки , как C++, C#, PHP , по умолчанию являются pass-by-value, как и вышеприведенные языки, но функции могут явно объявлять параметры как pass-by-reference, используя & или ref .
Perl всегда является pass-by-reference; однако на практике люди почти всегда копируют значения после их получения, таким образом используя их в pass-by-value-м способе.
Относительно J, в то время как существует только AFAIK, проходящий по значению, существует форма прохождения по ссылке, которая позволяет перемещать много данных. Вы просто передаете нечто, известное как locale, глаголу (или функции). Это может быть экземпляр класса или просто универсальный контейнер.
spaceused=: [: 7!:5 <
exectime =: 6!:2
big_chunk_of_data =. i. 1000 1000 100
passbyvalue =: 3 : 0
$ y
''
)
locale =. cocreate''
big_chunk_of_data__locale =. big_chunk_of_data
passbyreference =: 3 : 0
l =. y
$ big_chunk_of_data__l
''
)
exectime 'passbyvalue big_chunk_of_data'
0.00205586720663967
exectime 'passbyreference locale'
8.57957102144893e_6
Очевидным недостатком является то, что вам необходимо каким-то образом узнать имя вашей переменной в вызываемой функции. Но эта техника позволяет безболезненно перемещать большое количество данных. Вот почему, хотя технически не проходим по ссылке, я называю его "pretty much that".
PHP также передается по значению.
<?php
class Holder {
private $value;
public function __construct($value) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
}
function swap($x, $y) {
$tmp = $x;
$x = $y;
$y = $tmp;
}
$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);
echo $a->getValue() . ", " . $b->getValue() . "\n";
Выходы:
a b
Однако в PHP4 объекты рассматривались как примитивы . Какие средства:
<?php
$myData = new Holder('this should be replaced');
function replaceWithGreeting($holder) {
$myData->setValue('hello');
}
replaceWithGreeting($myData);
echo $myData->getValue(); // Prints out "this should be replaced"
По умолчанию ANSI/ISO C использует либо-это зависит от того, как вы объявляете свою функцию и ее параметры.
Если вы объявите параметры своей функции как указатели, то функция будет иметь значение pass-by-reference, а если вы объявите параметры своей функции как переменные без указателей, то функция будет иметь значение pass-by-value.
void swap(int *x, int *y); //< Declared as pass-by-reference.
void swap(int x, int y); //< Declared as pass-by-value (and probably doesn't do anything useful.)
Вы можете столкнуться с проблемами, если создадите функцию, которая возвращает указатель на нестатическую переменную, созданную внутри этой функции. Возвращаемое значение следующего кода будет неопределенным-нет никакого способа узнать, было ли перезаписано пространство памяти, выделенное для временной переменной, созданной в функции.
float *FtoC(float temp)
{
float c;
c = (temp-32)*9/5;
return &c;
}
Однако можно вернуть ссылку на статическую переменную или указатель, который был передан в списке параметров.
float *FtoC(float *temp)
{
*temp = (*temp-32)*9/5;
return temp;
}