referans ile bu geçmek ya da değeriyle geçmesi?

oy
48

Yeni bir programlama dili öğrenirken, karşılaşabileceğiniz olası Barikatlarımızdan bir soru dilidir olsun, varsayılan olarak, bir by-value-pass veya pass-by-referans .

Yani burada hepinize sorum favori dilinde, olduğu nasıl aslında yapılır? Ve ne mümkün tuzaklar ?

En sevdiğin dil, elbette, hiç ile oynamıştır şey olabilir: popüler , karanlık , ezoterik , yeni , eski ...

Oluştur 05/08/2008 saat 09:56
kaynak kullanıcı
Diğer dillerde...                            


11 cevaplar

oy
31

İşte için kendi katkıdır Java programlama dili .

İlk bazı kod:

public void swap(int x, int y)
{
  int tmp = x;
  x = y;
  y = tmp;
}

Bu neden olacaktır, bu yöntemi çağıran:

int pi = 3;
int everything = 42;

swap(pi, everything);

System.out.println("pi: " + pi);
System.out.println("everything: " + everything);

"Output:
pi: 3
everything: 42"

Hatta benzer bir sonuç gösterecektir 'gerçek' nesneleri kullanarak:

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"

böylece Java parametrelerini geçirir açıktır değere göre değeri olarak, pi ve her şey ve myObj nesneleri takas edilmez. "değeri" olduğunu unutmayın tek yolu bir yönteme parametreleri geçirmek için java. (örneğin, c ++ gibi bir dil 'kullanılarak, referans ile bu parametre geçirmek için geliştirici sağlar ve parametre türü sonra')

Şimdi zor kısmı veya yeni java geliştiricilerin çoğu karıştıracaktır bölüm en azından: (ödünç JavaWorld )
Orijinal yazarı: Tony Sintes

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"

Zor başarıyla pnt1 değerini değiştirir! Bu nesneler başvuruya göre iletilir geldiği anlamına geliyordu, bu durum böyle değil! Doğru deyimi olacaktır: Nesne başvuruları değer geçirilir.

Tony Sintes daha:

yöntem başarılı bir değeri geçtiği halde pnt1 değerini değiştirir; Ancak pnt1 ve pnt2 bir takas başarısız! Bu karışıklık önemli kaynağıdır. Ana () yöntemde, pnt1 ve pnt2 nesne referansları başka bir şey değildir. Eğer zor () yöntemine pnt1 ve pnt2 geçtikten sonra, Java gibi başka bir parametre gibi değeri referans geçer. Bu yönteme geçirilen referansların aslında orijinal referansların kopyaları olduğu anlamına gelir. Aşağıdaki Şekil 1, bir Java bir yöntemle bir nesne geçtikten sonra aynı nesneye işaret eden iki referans gösterilmektedir.

Şekil 1, http://www.javaworld.com/javaworld/javaqa/2000-05/images/03-qa-0512-pass2b.gif

Sonuç ya da kısa uzun bir hikaye:

  • Java o parametreleri geçer değeriyle
  • "değeri" olan tek yol için bir yönteme, bir parametre geçirmek için Java
  • kullanılarak nesneden yöntemler parametre olarak verilen değiştirecek referanslar orijinal nesneleri işaret olarak nesne. (bu yöntem kendisi bazı değerleri değiştirir ise)

kullanışlı bağlantılar:

Cevap 05/08/2008 saat 09:56
kaynak kullanıcı

oy
20

İşte için bir başka makale c # programlama dili

C # kendi bağımsız değişkenler geçirir değeri (varsayılan)

private void swap(string a, string b) {
  string tmp = a;
  a = b;
  b = tmp;
}

takası bu sürümünü çağıran böylece hiçbir sonuç olacaktır:

string x = "foo";
string y = "bar";
swap(x, y);

"output: 
x: foo
y: bar"

Ancak java aksine c # yapar geliştiriciye parametrelerini geçirmek için fırsat vermek referans ile , bu parametrenin türüne önce 'ref' anahtar sözcüğünü kullanarak yapılır:

private void swap(ref string a, ref string b) {
  string tmp = a;
  a = b;
  b = tmp;
} 

Bu takas edecek başvurulan parametrenin değerini değiştirin:

string x = "foo";
string y = "bar";
swap(x, y);

"output: 
x: bar
y: foo"

c # da vardır dışarı anahtar kelime ve Hakem ile dışarı arasındaki fark ince bir tanesidir. msdn:

Bir alan bir yöntemin arayan üzerinden parametre çağrı öncesinde parametre olarak geçirilen değişken atamak için gerekli değildir; Ancak Aranan edilir dönmeden önce dışarı parametresi atamak için gerekli.

ve

Buna karşılık ref parametreleri vardır başlangıçta atanmış olarak kabul tarafından Aranan. Bunun gibi, Aranan edilir ref atamak gerekli değildir Kullanmadan önce parametre. Ref parametreleri içine ve bir yöntemin dışında hem geçirilir.

Bu, küçük bir çukur, Java gibi bir değer geçirilir nesneleri hala kendi iç yöntemlerle değiştirilebilir

Sonuç:

  • c #, varsayılan olarak, parametrelerini geçer değeriyle
  • ancak gerekli parametreleri de geçirilebilir referans olarak ref anahtar sözcüğünü kullanarak
  • değer geçirilir bir parametre iç yöntemler değiştirecek nesne (bu yöntem kendisi bazı değerleri değiştirir ise)

kullanışlı bağlantılar:

Cevap 05/08/2008 saat 17:40
kaynak kullanıcı

oy
19

Python pass-by-değeri kullanır, ancak bu gibi tüm değerler nesne referansları olduğundan, net etkisi geçiş referans ile benzer bir şeydir. Ancak, Python programcıları bir nesne türü olup olmadığı hakkında daha fazla düşünmek değişken veya değişmez . Değişken nesneler, değişmez nesneler olamaz (örneğin, tam sayılar, dizeleri, küpe) oysa yerinde (örneğin, sözlükler, listeler, kullanıcı tanımlı nesneler) değiştirilebilir.

Aşağıdaki örnek, iki bağımsız değişmez bir dize ve kesilebilir bir listesini geçirilen bir fonksiyonunu göstermektedir.

>>> 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']

Çizgi a = "Red"sadece yerel bir isim yaratır a, dize değeri "Red"ve (aynı gizlenir geçirilen içinde argüman üzerinde hiçbir etkisi yoktur ao andan itibaren yerel isim başvurmalıdır). Atama bakılmaksızın argüman değişken veya değişmez olmasına bakmaksızın, bir yerinde operasyon değil.

bParametre kesilebilir bir liste nesnesi için bir referans ve .append()yöntem yeni teyel, listenin bir yerinde uzantısı yerine "Blue"dize değeri.

(Dize nesneleri değişmez olduğundan, yerinde değişiklikler destekleyen herhangi bir yöntem yoktur.)

Fonksiyon döndükten sonra, yeniden atama auzatılması iken, herhangi bir etkisi olmuştur baçıkça pass-by-referans tarzı çağrı semantik gösterir.

Argümanı bile, daha önce de belirtildiği gibi abir değişken türüdür işlev içinde yeniden atama yerinde operasyon değildir ve bu nedenle geçirilen argüman değerde değişiklik olacağını:

>>> a = ["Purple", "Violet"]
>>> do_something(a, b)
>>> print a, b
['Purple', 'Violet'] ['Black', 'Burgundy', 'Blue', 'Blue']

Aradığınız işlevi tarafından değiştirilmiş listenizi istemediğini, bunun yerine yerinde desteklemez (ziyade köşeli parantez yerine, hazır bilgi formu parantez tarafından tanımlanan) değişmez tuple türünü kullanmak istiyorsunuz .append()yöntemi:

>>> 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'
Cevap 23/08/2008 saat 17:50
kaynak kullanıcı

oy
7

Henüz Perl cevap görmedim beri, bir yazmak düşündüm.

Kapağın altında, Perl pass-by-referans olarak etkin bir şekilde çalışır. Işlev çağrısı bağımsız değişkenleri olarak Değişkenler sabitler salt okunur değerler olarak geçirilir ve ifadelerin sonuçları geçicilere olarak geçirilir, referentially geçirilir. Her zamanki deyimler gelen liste atama yoluyla argüman listeleri oluşturmak için @_suretiyle veya shiftgörünümünü veren kullanıcıdan bu gizlemek eğilimindedir pass-by-değeri:

sub incr {
  my ( $x ) = @_;
  $x++;
}

my $value = 1;
incr($value);
say "Value is now $value";

Bu yazdırılacaktır Value is now 1çünkü $x++içinde bildirilen sözcüksel değişken artırılır etti incr()fonksiyonu yerine geçirilen değişkeni. Bu pass-by-değerin tarzı çoğu zaman aranıyor genellikle budur, onların argümanları modifiye işlevleri Perl nadirdir olarak, ve stil kaçınılmalıdır.

Herhangi bir nedenle bu davranış, özellikle arzu edilir, ancak, bu elemanların doğrudan çalıştırılmasıyla elde edilebilir @_bu işlevi geçirilen değişkenler için takma olacaktır, çünkü bir dizi.

sub incr {
  $_[0]++;
}

my $value = 1;
incr($value);
say "Value is now $value";

Bu sefer yazdırır Value is now 2çünkü $_[0]++ifadesinin, gerçek artırılır $valuedeğişkeni. Bu yöntemin çalışması başlık altında olmasıdır @_(elde edilecek gibi diğer birçok diziler gibi gerçek bir dizi değil my @array), fakat bunun yerine unsurları bir işlev çağrısına geçilen argümanlar doğrudan dışarı inşa edilir. Bu, gerekli olacağını eğer pass-by-reference anlambilim oluşturmanıza olanak sağlar. Bu diziye olduğu gibi, ve sabitler veya daha karmaşık ifadelerin sonuçları salt okunur geçicilere olarak eklenen düz değişkenler Fonksiyon çağrısı argümanlar yerleştirilir.

Perl referans değerleri destekler çünkü pratikte bunu ancak son derece nadirdir; O, diğer değişkenleri ifade değerindedir. Normal olarak değişken bir referans geçen, bir değişken üzerinde belirgin bir yan etkiye sahip olan bir fonksiyon yapımı çok daha nettir. Bu callsite okuyucuya açık bir göstergesidir, bu geçiş ile referans semantik etkindir.

sub incr_ref {
  my ( $ref ) = @_;
  $$ref++;
}

my $value = 1;
incr(\$value);
say "Value is now $value";

Burada \operatör ile aynı şekilde bir referans verir &adresi-operatörü C.

Cevap 13/04/2012 saat 16:33
kaynak kullanıcı

oy
6

Bir var iyi bir açıklama buraya .NET için.

Birçok insan sürpriz olduğunu referans nesneleri aslında (her iki C # ve Java olarak) değer geçirilir. Bir yığın adresinin bir kopyası. nesne gerçekten işaret, ama yine de bir yöntem nesnenin değerlerini değiştirmek sağlar burada değiştirmesini bir yöntem engeller. C # olası nerede gerçek bir nesne noktaları değiştirmek anlamına gelir, referans ile bu başvuru, geçmek için.

Cevap 06/08/2008 saat 23:43
kaynak kullanıcı

oy
5

Orada da olduğunu unutmayın adıyla geçmesi ve değer sonuç geçmek .

Değer sonuç ile Geçiş değer parametresi olarak kabul edildi, orijinal değişkendeki ayarlandığını ilave yönü ile değeriyle geçmesi benzerdir. Bu, bir dereceye kadar, küresel değişkenler müdahaleyi önleyebilirsiniz. Bu referans bir geçiş, bir sayfa hatasına (neden olabilir Bölünmüş hafızanın, görünüşe göre daha iyi bir referans ).

Adıyla Geçiş aslında kullanıldığında değerleri sadece ziyade prosedürün başlangıcında daha hesaplanır anlamına gelir. Algol geçmek isme göre kullanılır, ancak ilginç bir yan etkisi çok zor bir takas işlemi (yazmaktır olan Referans ). Ayrıca, adı tarafından geçirilen sentezleme aynı zamanda yan etkileri olabilir erişildiği her sefer, yeniden değerlendirilir.

Cevap 05/08/2008 saat 11:00
kaynak kullanıcı

oy
4

Ne olursa olsun by-value-pass veya pass-by-referans dilleri arasında tutarlı olmalıdır olarak söylerler. Diller arasında en yaygın olarak kullanılan ve tutarlı tanım by-pass-referansla, bir işleve bir değişken geçirebilirsiniz olmasıdır "normal" ve işlev olabilir (açıkça adresi veya böyle bir şey almadan yani) atamak (mutasyona değil içerikleri) işlevi içinde parametre ve çağrı etki değişkene atama gibi aynı etkiye sahip olur.

şöyle Bu görünümde, diller gruplandırılmış; Aynı geçen anlam sahip olan her bir grubunu temsil eder. İki dil aynı grupta konması gerektiğini düşünüyorum, ben bunları ayıran bir örnek ile gelip meydan.

Dahil dillerin büyük çoğunluğu C , Java , Python , Ruby , JavaScript , Şema , OCaml , Standart ML , Git , Objective-C , Smalltalk vb tüm pass-by-değeri sadece . Bir işaretçi değerini (bazı diller o "referans" olarak adlandırılır) geçen referans ile bu geçiş olarak kabul etmez; Geçirmeye şey hakkında sadece endişe, işaretçi, bırakma olayı işaret etti.

Gibi diller C ++ , C # , PHP pass-by-değerin üzerinde diller gibi, varsayılan olarak, ancak işlevleri açıkça, referans ile-pass kullanarak olmaya parametreleri ilan edebilir &ya ref.

Perl her geçiş referans ile olduğu; Ancak pratikte insanların hemen hemen her zaman bu şekilde, bunu elde devretmek by-value şekilde kullandıktan sonra değerleri kopyalayın.

Cevap 13/04/2012 saat 21:00
kaynak kullanıcı

oy
4

değeriyle

  • Sistem parametresi kopyalamak için sahip olduğu, referans ile daha yavaştır
  • girişi için kullanılan tek

referans olarak

  • Daha hızlı sadece işaretçi geçirilir beri
  • girişi için kullanılan ve çıkış
  • Küresel değişkenler ile birlikte kullanıldığında ise çok tehlikeli olabilir
Cevap 05/08/2008 saat 10:10
kaynak kullanıcı

oy
3

İlgili J sadece orada ise AFAIK, değeriyle geçen çok veri hareket sağlayan referans ile geçen bir şekli vardır. Sadece bir fiil (ya da fonksiyon) bir yerel ayar olarak bilinen şey geçmektedir. Bu sınıfın bir örneği ya da sadece genel bir kap olabilir.

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

bariz dezavantajı aradığınız işlevinde bir şekilde sizin değişkenin adını bilmek gerekir olmasıdır. Ama bu teknik acısız çok fazla veri taşıyabilirsiniz. teknik olarak referans olarak geçemez iken, ben "bu gerçekten çok" diyorlar, budur.

Cevap 21/11/2009 saat 18:14
kaynak kullanıcı

oy
2

PHP de değeriyle geçmesi edilir.

<?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";

Çıktılar:

a b

Ancak PHP4'te nesneler gibi tedavi edildi ilkel . Bu da demektir ki:

<?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"
Cevap 11/08/2008 saat 03:21
kaynak kullanıcı

oy
-1

Varsayılan olarak, ANSI / ISO C ya kullanır - bu size işlevini ve parametrelerini beyan bağlıdır.

Eğer işaretçiler olarak işlev parametreleri beyan sonra işlev pass-by-referans olacak ve sen-işaretçi değişkenler olarak işlev parametreleri bildirirseniz daha sonra işlevi pass-by-değeri olacaktır.

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.)

Eğer bu işlevin içinde oluşturulan bir statik olmayan değişkene gösterici döndüren bir işlev oluşturursanız sorunlarla çalıştırabilirsiniz. Aşağıdaki kod döndürülen değer tanımsız olur - işlevinde oluşturulan geçici değişken için ayrılan bellek alanı üzerine ya olmasaydı bilmenin bir yolu yoktur.

float *FtoC(float temp)
{
    float c;
    c = (temp-32)*9/5;
    return &c;
}

Ancak, statik bir değişken veya parametre listesindeki geçirildi işaretçisi bir başvuru geri dönebilirler.

float *FtoC(float *temp)
{
    *temp = (*temp-32)*9/5;
    return temp;
}
Cevap 13/01/2011 saat 21:48
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more