Kafamı Dokunulmazlık Etmek


13

Nesneye yönelik programlamaya yeniyim ve kavramak için biraz zamanımı alan bir kavram değişmezlik. Sanırım ampul dün gece söndü ama doğrulamak istiyorum:

Değişmez bir nesnenin değiştirilemeyeceğine dair ifadelerle karşılaştığımda, örneğin aşağıdakileri yapabileceğim için şaşkınım:

NSString *myName = @"Bob";
myName = @"Mike";

Orada, değiştirilemez tipte NSString adımı değiştirdim. Benim sorunum, "nesne" sözcüğü bellekte fiziksel nesneye veya "myName" soyutlama anlamına gelebilir. Önceki tanım değişmezlik kavramı için geçerlidir.

Değişkene gelince, değişmezliğin daha açık (bana göre) bir tanımı, değişmez bir nesnenin değerinin sadece hafızadaki yerini, yani referansını (işaretçisi olarak da bilinir) değiştirerek değiştirilebilmesidir.

Bu doğru mu, yoksa hala ormanda kayboldum mu?


13
Senin türün bir değil NSString, değişmez bir " işaretçi ve NSString" dir. Ben objektif C şey bilmiyorum, ama senin örnekte tahmin ediyorum @"Mike"yeni bir örneğini oluşturuyor NSStringve atamadan pointer , myName. Yani myNameişaret eden nesneyi , sadece işaret ettiği nesneyi değiştirmediniz .
fwgx

2
@fwgx Bir cevap olarak koyun, benim oyumu alacaksınız.
Gulshan

Tüm cevaplar için herkese teşekkür ederim, çok yardımcı oldular. Şimdi değişmez nesnenin, onu gösteren değişken değil, bellekteki değer olduğunu uderstand.
Michael Mangold

@Gulshan Done, aşağıya bakın ....
fwgx

Değişmezliği anlamak için, bağlanabilirliği net bir şekilde ayıran (yani, nesnelere isim vererek) (yani bir adın farklı bir nesneye yeniden atanmasına izin veren) bir programlama dili öğrenmenizi öneririm. ML (herhangi bir şekilde: SML, Ocaml, F #) iyi bir örnektir.
Gilles 'SO- kötü olmayı kes'

Yanıtlar:


4

Kulağa doğru yöne gidiyormuşsunuz gibi geliyor, ama henüz tam olarak anlamadım. Bu yanlış:

Orada, değiştirilemez tipte NSString adımı değiştirdim. Benim sorunum, "nesne" sözcüğü bellekte fiziksel nesneye veya "myName" soyutlama anlamına gelebilir.

Kod snippet'inizde, myNamedeğiştirilemez tipte NSStringdeğil, değiştirilebilir tipte NSString*(NSString'e işaretçi). Kaybettiğiniz en önemli şey, bir işaretçinin sadece başka bir değer olduğunu anlamaktır ve işaret ettiği şeyden (veya yaşamı boyunca kısmen değiştirirseniz) tamamen ayrı bir hayata sahiptir .

Diyorsun:

... değişmez bir cismin değeri sadece hafızadaki yerini değiştirerek, yani referansını (işaretçisi olarak da bilinir) değiştirerek değiştirilebilir.

Bu yanlış. Bir nesne değil kendi işaret eden konu bu, ne de bir nesnenin hafıza alanıdır kontrollü Bunda herhangi işaretçiler ile veya başka etkiledi.

Dolayısıyla, NSStringörneğinizdeki ( @"Bob"ve @"Mike") iki nesne myNamedeğişkenten tamamen ayrıdır . Ayrıca birbirlerinden tamamen ayrıdırlar. Eğer değiştirdiğinizde myNameiçin noktaya @"Mike"işaret ederek yerine @"Bob", sen değişikliğe uğramayan NSStringnesneleri.


Bütünlüğü sağlamak için, o çöp toplayıcılar bu daha karmaşık işaretçiler bu değişiklikler yaratmaz olabilir için onlar işaret nesneleri (ed) etkiler. Ancak bu, kodun gözlemlenebilir davranışını etkilememesi gereken bir uygulama ayrıntısıdır.


17

Kelimelerle kayboldun. Değişmezlik şu anlama gelir: Değişkeni değiştirmediğiniz sürece, diğer değişkenlerle ne yaparsanız yapın her zaman aynı değeri "içerecektir".

C'deki karşı örnek (buna izin veren bir mimari varsayarak biraz basitleştirilmiş):

 char *a = "Hello World";
 char *b = a;
 b[0] = 'Y';

Artık artık "Merhaba Dünya" dizesini "içermiyor" (yani, işaret ediyor), ama bunun yerine "Yello World".

Dizelerin değiştirilemediği dillerde, örneğin Java ve (EDIT: safe) C # gibi, bunu yapamazsınız. Olmaz. Bu, programın her bölümünün dizeye güvenli bir şekilde referans tutabileceği ve içeriğinin asla değişmediğine güvenebileceği anlamına gelir; aksi takdirde, sadece güvenli tarafta olmak için bir kopya oluşturmaları gerekir.

Ancak değişken hala değişkendir. Başka bir nesneyi göstermesine izin verebilirsiniz. Sadece nesnenin kendisi arkanızda değişmeyecek.


1
Teknik olarak dize içeriğini C # ' da değiştirebilirsiniz, sadece unsafekod kullanmanız gerekir .
Aaronaught

1
Aaronaught: Bilgi için teşekkürler, haklısın; bilmesi gereken herkes için: msdn.microsoft.com/en-us/library/ms228599.aspx
user281377

10

Değişkenleri nesnelerle karıştırıyorsunuz. Değişkenler nesnelere başvuruları saklamak için kullanılabilir, ancak nesneler DEĞİLDİR. Değişken değil değişmez nesnelerdir, bu nedenle değişkeni bir nesneden diğerine değiştirebilirsiniz, ancak değişmezse nesnenin niteliklerini değiştiremezsiniz.

Nesneyi yüksek, sarhoş bir komşu olarak düşünün. Makul (değişebilir) ise, kapısını çalabilir ve onu fazla gürültü yapmadığı bir yaşam tarzına dönüştürebilirsiniz. Ama değişmezse, tek değişikliğiniz başkasının harekete geçmesini ummaktır!


3
Susturmak isterdim bazı komşularım vardı.
Dave Nay

Açıklamanız yeterince iyi olduğu için ikinci paragrafta örneğinize ihtiyacınız olduğunu düşünmüyorum. IMO örneği sadece kafa karıştırıcı olabilir. Ancak chap'ın sorusuna kısa ve öz bir cevap için +1.
Paul McCabe

@DaveNay: Gizli cinayet için özür dilerim. Hiç tasarlanmamıştı.
Kilian Foth

6

Değişken bir nesne değildir. Değişken, bir nesneye (veya daha genel olarak bir değere) karşılık gelen bir addır.

Örneğin "kaleci", hedefi savunmaktan sorumlu nesneyi (kişiyi) ifade etmek için kullandığımız bir isimdir. Ama o kişiyi bir başkasıyla değiştirirsem (eski ya da yaralı olmadığı için), yeni kişiye artık "kaleci" denir.

Atama ifadesi değişkenleri değişken kılan şeydir (Haskell gibi bazı diller buna sahip değildir ve aslında değişmez değişkenler kullanır). Bir adın anlamını yeniden tanımlamanızı ve böylece değeri yeniden atamanızı sağlar.

Şimdi nesnelerin kendileri değişmez olabilir . Birkaç bin yıl önce elmasların değişmez olduğunu düşünebilirdi. Bir elmasla ne yaparsanız yapın, onu değiştiremezsiniz. İster waggawooga olarak adlandırın (kabilenin en büyük parlak taşına gevşekçe çevirir) ya da bu şekilde demeyi bıraktınız (çünkü daha büyük bir tane buldunuz), elmas aynı kaldı. Bunun aksine, waggawooga'nızla komik resimlerde oymak için kullandığınız odun parçası aynı kalmadı. Değişken olduğunu kanıtladı. Her zaman aynı isme sahip olsa bile.

Hem değişkenler hem de değerler değiştirilemez (bağımsız olarak). Bu durumda değişmez olan nesnelerdir. Bir kez oluşturduktan sonra NSStringdeğiştiremezsiniz. İsimler diyebilir ve aktarabilirsiniz, ancak aynı kalır. Bunun aksine, NSMutableStringoluşturmadan sonra, örneğin setStringyöntemi çağırarak değiştirilebilir .


Waggawooga karşılaştırmasını seviyorum!
Michael K

Orijinal posteri gerekenden daha fazla karıştırmamak için: bir değişkenin bir nesne olmadığı noktanız iyi olsa da, bir değişken aslında "bir değere karşılık gelen bir ad" olarak tanımlanmaz. Bir değişken büyük olasılıkla adlandırılır ve değer içeren bir depolama konumuna karşılık gelir . Birçok programlama dilinde değişkenlerin adlandırılması gerekmez ve birçok dilde aynı değişkenin birden fazla adı olabilir.
Eric Lippert

4

Sanırım kaybolmuş hissediyorsunuz, çünkü iki kavramı karıştırıyorsunuz: nesnenin kendisi ve o nesneye bağlı değişken adı.

Değişmez nesneler değiştirilemez. Dönemi. Bununla birlikte, değişmez bir nesneye bağlı değişken adı (sembol), başka bir değişmez nesneye bağlı olacak şekilde değiştirilebilir .

Başka bir deyişle, bu iki satırda yaptığınız şey şuydu:

  1. "Bob" değeriyle değişmez dize nesnesi oluşturma
  2. sembolü myNameo nesneye bağla
  3. "Mike" değeriyle değişmez dize nesnesi oluşturma
  4. sembolü myNameo nesneye bağla

2

Sizin senin tipin bir değil NSString, bir "olduğunu, işaretçi bir NSStringdeğişmez değildir". Ben objektif C hiçbir şey bilmiyorum, ama örnekte @"Mike"yeni bir örnek oluşturma NSStringve işaretçiye atama olduğunu tahmin ediyorum myName. Eğer nesne değişmemiştir Yani myNameedildi işaret lazım, neyi o işaret edildi.


0

İşte değiştirilebilir bir nesne örneği: charC dizisi :

char str[10];

İçeriğinistr kalbimin içeriğine göre değiştirebilirim (10 karakterden fazla olmadığı sürece). C dizesi kitaplığı işlevleri tarafından bir dize olarak tanınabilmesi için, sondaki 0 ​​olması gerekir, böylece 9 karakter uzunluğunda dizeleri tutabilir:

strcpy(str, "hello"); // str now contains the string "hello\0"
strcpy(str, "world"); // str now contains the string "world\0"

str[0] = 'W';         // str now contains "World\0"

ve böylece weiter .

Bunu Java'daki bir dize nesnesiyle karşılaştırın:

String foo = "Hello";

Dize örneği ('H', 'e', ​​'l', 'l' ve 'o' karakterlerini içeren bellek yığını değiştirilemez; Bu dizenin içeriğini değiştiremiyorum. Gibi bir şey yazdığınızda

foo = foo + " World";

"Merhaba" örneğinin sonuna "Dünya" ifadesini eklemiyorsunuz; yeni bir örnek oluşturuyorsunuz , "Merhaba Dünya" yı kopyalıyor ve foobu yeni dize örneğine başvuracak şekilde güncelleniyorsunuz .

fookendisi dize örneğini içermez; yalnızca bu örneği belirtir (C veya Obj-C'deki bir işaretçiye benzer), bu nedenle String gibi türlere neden referans türleri denir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.