|
|||
| Previous < |
Contents ^
|
Next >
|
|
songslara ihtiyacı olduğunu
tespit etti. Bu yüzden öncelikle şarkıları temsil eden bir Ruby sınıfı oluşturmamız daha doüru gibi gözüküyor.
Gerçek bir şarkının ismi, yorumcusu ve bie süresi olduğunu biliyoruz, o yüzden programımızdaki şarkı nesnelerinin de bu özelliklere sahip olmasını sağlamalıyız.
Öncelikle sadece basit bir initialize metoduna sahip olan basit bir Song sınıfı yaratmakla başlıyoruz
[Sayfa 9'da bahsettiğimiz gibi sınıf isimleri büyük harfle başlarken, metot isimleri küçük harfle başlıyor.]
class Song def initialize(name, artist, duration) @name = name @artist = artist @duration = duration end end |
initialize, Ruby programlarında bulunan özel bir metottur. Yeni bir Song nesnesi yaratmak için
Song.new'i çağırdığınızda, Ruby hazırlanmamış bir nesne yaratır ve daha sonra new'e geçtiğimiz tüm parametrelerle birlikte
nesnenin initialize metodunu çağırır. Bu, nesnenin durumunu belirleyebileceğiniz kodlar yazmanıza izin verir.
Song sınıfı için, initialize metodu üç parametre alır. Bu parametreler
metodun içindeki yerel değişkenler gibi davrnırlar, bu yüzden de yerel değişkenleri adlandırma kuralına göre; yani küçük harfle başlayarak adlandırılmışlardır.
Her bir nesne bir şarkıyı temsil eder, bu yüzden her bir Song nesnesinin kendi şarkı adını, yorumcusunu ve
süresini taşımasını sağlamalıyız. Bu da, bu değerleri nesnenin içine örnek değişkenler gibi yerleştirmemiz
gerektiği anlamına gelir. Ruby'de bir örnek değişken, isminin başına bir salyangoz işareti (``@'') alarak oluşturulur.
Bizim örneğimizde, name parametresi @name'e, artist @artist'e
ve duration (şarkının saniye olarak uzunluğu)@duration örnek değişkenine atanmıştır.
Şimdi yeni sınıfımızı test edelim:
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.inspect
|
» |
"#<Song:0x401b4924 @duration=260, @artist=\"Fleck\", @name=\"Bicylops\">"
|
inspect mesajı her nesneye gönderilebilinen
bir mesajdır ve nesnenin id'si ile örnek değişkenlerini ortaya çıkarır. Hepsini doğru kurmuşuz gibi gözüküyor.
Deneyimlerimiz bize, geliştirme sırasında bir Song nesnesinin içeriğini defalarca ekrana yazdıracağımızı ve
inspect 'in varsayılan biçiminin beklenen birşeyler bıraktığını söylüyor. Neyse ki, to_s
adında, nesneye bir dizgi sunmak istediğini söyleyen standat bir mesajımız var. Şimdi bu mesajı kendi şarkımızda deneyelim:
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.to_s
|
» |
"#<Song:0x401b499c>"
|
to_s'yi kendi
sınıfımız için yeniden yazalım. Bunu yapmadan önce, bir kaç dakika bu kitap boyunca sınıfları nasıl göstereceğimizden bahsedelim:
Ruby'de sınıflar asla kapanmaz: her zaman için varolan bir sınıfa yeni metotlar ekleyebilirsiz. Bu hem sizin oluşturduğunuz
sınıflar için hem de standart, built-in sınıflar için geçerlidir. Tek yapmanız gereken şey, varolan bir sınıf
için bir sınıf tanımlaması açmak ve yeni özellikleri eklemektir.
Bu amaçlarımız için iyi bir durumdur. Bu bölüm boyunca, eski sınıf tanımlamalarımız hala dururken, onlara
yeni özellikler ekleyip, yeni metotlar için sadece sınıf tanımlamasını göstermek işimize yarayacaktır.
Bu bize, her örnekte gereksiz tanımlamalar yapmaktan koruyacaktır. Düşünün, eğer bu durumdan habersizce, bu kodu
sıfırdan yazmanız gerekseydi, muhtemelen tüm metotları tek bir basit sınıf yapısına atardınız.
Bu kadar detay yeter! Şimdi Song sınıfımıza bir to_s metodu eklemeye devam edelim:
class Song
|
||
def to_s
|
||
"Song: #{@name}--#{@artist} (#{@duration})"
|
||
end
|
||
end
|
||
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.to_s
|
» |
"Song: Bicylops--Fleck (260)"
|
to_s'yi desteklediğini söyledik ancak bunu nasıl yaptığından bahsemedik.
Bunun cevabını mirasla, altsınıflamayla ve bir nesneye bir mesaj gönderdiğinizde Ruby'nin bunu nasıl
saptadığıyla açıklamamız gerekiyor. Bu da yeni bir bölüm demek, öyleyse...
Song sınıfına yerleştirdiğimiz şarkı içeriğine sahiptir.
Daha sonra pazarlama işi devreye girer ve müzik kutumuza karaoke desteği eklememiz gerektiğini söyler. Bir karaoke
şarkısı da aynı diğerlerine benzer (sadece vokal yoktur, ama bu kısmı bizi ilgilendirmiyor).
Ancak, zaman ve şarkı sözleriyle ilişkili bir bağlantıya sahiptir. Müzik kutumuz bir karaoke şarkısı çalarken
şarkı sözleri, müzik kutusunun ekranında müzikle aynı anda gösterilmelidir.
Bu problemi halletmek için, tıpkı Song'a benzer, ancak şarkı sözü desteğiyle beraber KaraokeSong adında bir sınıf oluşturabiliriz.
class KaraokeSong < Song def initialize(name, artist, duration, lyrics) super(name, artist, duration) @lyrics = lyrics end end |
< Song'' satırı, Ruby'ye KaraokeSong'un, Song sınıfının
bir alt sınıfı olduğunu belirtiyor. (Şaşırtıcı olmayan bir şekilde, bu ayrıca Song'un,
KaraokeSong'un süper sınıfı olduğu anlamına gelir. İnsanlar ayrıca çocuk-ebeveyn ilişkinden bahsederler,
bu durumda KaraokeSong'un ebeveyni Song sınıfı olacaktır.) Şimdilik, initialize
metodu hakkında fazla kafa yormayın, bu super çağrıyla daha sonra ilgileneceğiz.
Şimdi bir KaraokeSong yaratalım ve kodumuzun çalışıp çalışmadığını görelim. (Son sistemde,
tüm şarkı sözleri metin ve zaman bilgisini içeren bir nesnede tutulacaktır. Sınıfımızı test etmek için,
sadece bir dizgi kullanacağız. Bu tipi olmayan (untyped) dillerin başka bir özelliğidir--kodu çalıştırmaya başlamadan önce
herşeyi tanımlamak zorunda değilsiniz.)
aSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...")
|
||
aSong.to_s
|
» |
"Song: My Way--Sinatra (225)"
|
to_s metodu neden şarkı sözlerini göstermedi?
Bu sorunun cevabı, Ruby'nin bir nesneye bir mesaj gönderdiğinizde hangi metodun çağrılacağına nasıl karar verdiğiyle
açıklanabilir. Ruby, aSong.to_s metodunu derlediğinde, aslında to_s metodunun tam olarak
nerede bulacağını bilmez. Üstelik, karar vermeyi program çalışıncaya kadar erteler.
Önce, aSong'un sınıfına bakar. Eğer bu sınıf, mesajla aynı adı içeren bir metot içeriyorsa,
o metot çalıştırılır. Eğer bulunamazsa, bu metodu bir üst ebeveyninde arar, eğer bulumazsa onun da bir üst ebeveyninde; bu durum
ata zincirinin en üstüne kadar devam eder.
Eğer, atalarında da eşleşen bir metot bulamazsa, normalde hata verecek özel bir durumla karşılık verir.
[Aslında, runtime sırasında bu hatanın önüne geçebilirsiniz. Daha fazla bilgi için, sayfa 355'deki
Object#method_missing
bölümüne bakın.]
Şimdi örneğimize geri dönelim. KaraokeSong sınıfının bir nesnesi olan aSong nesnesine
to_s mesajını gönderdik. Ruby, KaraokeSong sınıfında, to_s adında bir
metot aradı, fakat bulamadı. Bunun üzerine yorumlayıcı, KaraokeSong'un ebeveyni olan Song
sınıfına bakıyor ve sayfa 18'de tanımladığımız to_s metodunu buluyor.
İşte bu yüzden, şarkı detaylarını ekrana yazdığı halde, şarkı sözlerini yazmıyor-- Song sınıfı
şarkı sözleri hakkında hiçbir bilgiye sahip değil.
Şimdi, KaraokeSong#to_s metodunu gerçekleştirelim. Bunu yapabilmek için birçok yol mevcut.
Kötü bir yolla başlayalım. Song sınıfından to_s metodunu kopyalayalım ve şarkı sözünü ekleyelim.
class KaraokeSong
|
||
# ...
|
||
def to_s
|
||
"KS: #{@name}--#{@artist} (#{@duration}) [#{@lyrics}]"
|
||
end
|
||
end
|
||
aSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...")
|
||
aSong.to_s
|
» |
"KS: My Way--Sinatra (225) [And now, the...]"
|
@lyrics'in değerini doğru olarak gösterebiliyoruz. Bunu yapmakla, alt sınıfın
atalarının örnek değişkenlerine direkt olarak ulaşmasını sağladık. Peki öyleyse, to_s metodunu bu şekilde
gerçekleştirmek neden kötü bir yoldur?
Bunun cevabı, iyi programlama stiliyle ilgilidir (decoupling diye de adlandırılır).
Örneğin, Song'u şarkı sürelerini milisaniyeler şeklinde gösterecek şekilde değiştirdiğimizi düşünelim.
Aniden KaraokeSong gülünç değerler vermeye başlayacaktır. ``My Way''in karaoke versiyonunun 3750 dakika sürmesi
düşüncesi bile yeterince ürkütücü.
Bu problemi, her sınıfın kendi iç durumuna sahip olmasıyla çözüyoruz. KaraokeSong#to_s çağırıldığı zaman
şarkı detayları için onun ebeveyni olan Song sınıfının to_s metoduna başvuruyoruz.
Böylece şarkı sözü bilgisine, şarkının detaylarını da ekleyerek bize sonucu geri döndürüyor. Buradaki
küçük hilemiz, Ruby'nin ``super'' anahtar kelimesi olacaktır. super'i argüman olmaksızın
çağırırsanız, Ruby nesnenin ebeveynine bir mesaj gönderir ve o anki metoda geçilmiş olan parametreleri de
geçerek, metotla aynı isimde olan bir metot çağırır. Şimdi yeni ve geliştirilmiş to_s metodumuzu gerçekleştirebiliriz.
class KaraokeSong < Song
|
||
# Format ourselves as a string by appending
|
||
# our lyrics to our parent's #to_s value.
|
||
def to_s
|
||
super + " [#{@lyrics}]"
|
||
end
|
||
end
|
||
aSong = KaraokeSong.new("My Way", "Sinatra", 225, "And now, the...")
|
||
aSong.to_s
|
» |
"Song: My Way--Sinatra (225) [And now, the...]"
|
KaraokeSong'un Song sınıfının bir alt sınıfı olduğunu söyledik ancak
Song için bir ebeveyn belirlemedik. Eğer bir sınıf tanımlarken, bir ebeneyn belirtmezsek,
Ruby varsayılan olarak Object sınıfını atar. Bu da tüm nesnelerin ata olarak Object
sınıfına sahip olduğu ve bu sınıfın tüm örnek metotlarının Ruby'deki her nesne için geçerli olduğu anlamına gelir.
Sayfa 18'de to_s metodunun tüm nesneler için geçerli olduğundan bahsetmiştik. Niçin bilinmez,
to_s metodu Object sınıfındaki 35'i aşkın metottan biridir.
Tam liste, sayda 351'den itibaren belirtilmiştir.
Song sınıfının örnekleri gibi
nesnelerle uğraşalım.
Song nesneleri iç durumlar içeriyordu (şarkı ismi ve yorumcusu gibi).
Bu durumlar, bu nesnelere özgüydü---yani başka hiçbir nesne bu nesnelerin örnek değişkenlerine erişemezdi.
Genel olarak bakıldığında, bu İyi Birşeydir. Bu, bir nesnenin sadece kendi tutarlılığından sorumlu olması
anlamına gelir.
Ancak, tamamen ketum bir nesne, oldukça kullanışsızdır---bir defa onu yaratırsınız, ancak daha sonra hiçbirşey
yapamazsınız. Normal olarak, bir nesnenin durumuna erişebileceğiniz ve yönlendirebileceğiniz metotlar tanımlarsınız.
Nesnenin bu görülebilen harici yönlerine nitelikleri denir.
Song nesnelerimiz için ihtiyacımız olan ilk şey, şarkının adını, yorumcusunu (böylece şarkı çalarken
gösterebiliriz) ve süresini (ilerleme çubuğu gibi birşey gösterebiliriz) bulabilmektir.
class Song
|
||
def name
|
||
@name
|
||
end
|
||
def artist
|
||
@artist
|
||
end
|
||
def duration
|
||
@duration
|
||
end
|
||
end
|
||
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.artist
|
» |
"Fleck"
|
aSong.name
|
» |
"Bicylops"
|
aSong.duration
|
» |
260
|
attr_reader bu erişgeç metotlarını sizin için sağlar.
class Song
|
||
attr_reader :name, :artist, :duration
|
||
end
|
||
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.artist
|
» |
"Fleck"
|
aSong.name
|
» |
"Bicylops"
|
aSong.duration
|
» |
260
|
:artist construct'ı, artist'e karşılık gelen
bir Symbol nesnesine döndüren bir ifadedir. :artist'i, değişken artist'in bir adı
olarak düşünürken, artist'i de değişkenin değeri olarak düşünebilirsiniz.
Bu örneğimizde, erişgeç metotlarımızı name, artist ve duration
olarak adlandırdık. Bunlara karşılık gelen örnek değişkenler; @name, @artist ve
@duration otomatik olarak yaratılırlar.
Bu erişgeç metotları, önceden elle yazdıklarımızla tıpatıp aynıdır.
Song
nesnemizin içine yerleştiriyoruz.
C++ ya da Java gibi dillerde, bu işi kurucu fonksiyonlarla yaparsınız.
class JavaSong { // Java code
private Duration myDuration;
public void setDuration(Duration newDuration) {
myDuration = newDuration;
}
}
s = new Song(....)
s.setDuration(length)
|
aSong.name'deki
gibi gördük. Öyleyse, bir nitaliğe yeni bir değer vermek istediğinizde bu değişkenlere atamak çok doğal
bir iş olacaktır. En Az Sürpriz Prensibi'ne bağlı kalarak, Ruby'de yaptığınız herşey budur.
class Song
|
||
def duration=(newDuration)
|
||
@duration = newDuration
|
||
end
|
||
end
|
||
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.duration
|
» |
260
|
aSong.duration = 257 # set attribute with updated value
|
||
aSong.duration
|
» |
257
|
aSong.duration = 257'' ataması, 257'yi argüman olarak geçerek aSong nesnesinin duration=
metodunu çağırır. Aslında bir metot ismini sonunda eşittir işaretiyle tanımlamak, bu ismi, atamanın sol-el tarafında
görülmesini uygun kılar.
Tekrar belirtelim, Ruby bu basit nitelik kurma metotları için bir kısayol sağlar.
class Song
attr_writer :duration
end
aSong = Song.new("Bicylops", "Fleck", 260)
aSong.duration = 257
|
class Song
|
||
def durationInMinutes
|
||
@duration/60.0 # force floating point
|
||
end
|
||
def durationInMinutes=(value)
|
||
@duration = (value*60).to_i
|
||
end
|
||
end
|
||
aSong = Song.new("Bicylops", "Fleck", 260)
|
||
aSong.durationInMinutes
|
» |
4.333333333
|
aSong.durationInMinutes = 4.2
|
||
aSong.duration
|
» |
252
|
durationInMinustes herhangi bir nitelik gibi gözüküyor. Ancak, aslında örnek değişkene tekabül eden
hiçbir şey yok.
Burada meraktan daha fazlası yatar. Bertrand Meyer, nirengi noktası olan kitabı Object-Oriented Software Construction 'nda
bunu Değişmeyen Erişim Prensibi olarak tanımlar.
Örnek değişkenlerle hesaplanmış değerler arasındaki farkı gizlemekle, sınıfınızın gerçekleştirimini
dış dünyanın geri kalanından korumuş olursunuz. Gelecekte; sınıfınızı kullanan milyonlarca satır kodu etkilemeden
istediğiniz şeylerin nasıl çalıştığını değiştirmekte serbestsiniz. Bu büyük bir kazançtır.
@@count'' gibi iki ``salyangoz'' işaretiyle başlar.
Global ve örnek değişkenlerin tersine, sınıf değişkenleri kullanılmadan önce başlangıç değeri verilmelidir.
Genellikle bu hazırlama, sınıf tanımlaması içinde basit bir atamayla yapılır.
Örneğin, müzik kutumuz her bir şarkının kaç kere çalındığını kaydetmek istiyor. Bu sayaç muhtemelen
Song nesnesinin bir örnek değişkeni olabilir. Şarkı çalındığı zaman, örnek değişkenimiz
artar. Ancak aynı zamanda toplamda ne kadar şarkının da çaldığını bilmek istiyoruz. Bu işi, tüm Song nesnelerini
taratıp sayaçlarını ekleyerek ya da Tanrı'nın Kilisesi Planı'na göre bir risk alıp global bir değişken
kullanarak halledebiliriz. Ya da, bir sınıf değişkeni kullanabiliriz.
class Song @@plays = 0 def initialize(name, artist, duration) @name = name @artist = artist @duration = duration @plays = 0 end def play @plays += 1 @@plays += 1 "This song: #@plays plays. Total #@@plays plays." end end |
Song#play'in şarkının kaç kere çaldığı bilgisini ve toplamda tüm şarkıların
çalma sayısını tutan bir dizgiyi döndürecek biçimde düzenledik. Bunu kolayca test edebiliriz.
s1 = Song.new("Song1", "Artist1", 234) # test songs..
|
||
s2 = Song.new("Song2", "Artist2", 345)
|
||
s1.play
|
» |
"This song: 1 plays. Total 1 plays."
|
s2.play
|
» |
"This song: 1 plays. Total 2 plays."
|
s1.play
|
» |
"This song: 2 plays. Total 3 plays."
|
s1.play
|
» |
"This song: 3 plays. Total 4 plays."
|
new metodu, kendisi herhangi bir şarkıyla ilişkilendirilmediği halde
bir Song nesnesi yaratıyordu.
aSong = Song.new(....) |
File sınıfının
nesneleri belli başlı dosya sistemindeki açık dosyaları temsil eder. Ancak, File sınıfı aynı zamanda
açık olmayan dosyalar için ya da bir File nesnesine sahip olmayanlar için birçok metot sağlamaktadır.
Eğer bir dosyayı silmek istiyorsanız,
File.delete
sınıf metodunu çağırırsınız.
File.delete("doomedFile")
|
class Example def instMeth # instance method end def Example.classMeth # class method end end |
SongList adında bir metot
tanımlayabiliriz. Bu limiti, sınıf içinde başlangıç değeri verdiğimiz basit bir sabit (sabitleri hatırlayın?
büyük harfle başlarlar) bir sınıf sabitiyle koyuyoruz.
class SongList
|
||
MaxTime = 5*60 # 5 minutes
|
||
|
||
def SongList.isTooLong(aSong)
|
||
return aSong.duration > MaxTime
|
||
end
|
||
end
|
||
song1 = Song.new("Bicylops", "Fleck", 260)
|
||
SongList.isTooLong(song1)
|
» |
false
|
song2 = Song.new("The Calling", "Santana", 468)
|
||
SongList.isTooLong(song2)
|
» |
true
|
Logger.create'i çağırmaktır,
böylece sadece bir adet kayıt nesnesi oluşturulduğundan emin oluruz.
class Logger private_class_method :new @@logger = nil def Logger.create @@logger = new unless @@logger @@logger end end |
Logger'ın new metodunu özel (private) yaparak, geleneksel constructor kullanan
kullanarak bir kayıt nesnesi yaratmaya çalışan herşeyin önüne geçmiş oluruz. Yerine, Logger.create
adında bir sınıf metodu sağlıyoruz. Bu metot, her çağırıldığında bu örneği döndüren, kayıtın bir örneğinin bir
referansını tutan @@logger sınıf değişkenini kullanır.
[Burada gerçekleştirdiğimiz tekiller (singleton) iş parçacığı (thread)korumalı değildir; eğer çoklu
İş parçacıkları koşuyorsa, çoklu kayıt nesneleri tanımlamak daha uygun olacaktır. İş parçacıklarının güvenliğini
kendimiz sağlamak yerine, sayfa 468'den itibaren bahsettiğimiz Ruby'nin Singleton mixin'ini
kullanabilirsiniz.]
Logger.create.id
|
» |
537766930
|
Logger.create.id
|
» |
537766930
|
Shape sınıfı üzerinde duralım.
Shape'in örnekleri, kenar sayısı ve çevresini constructor'a vermek suretiyle yaratılırlar.
class Shape def initialize(numSides, perimeter) # ... end end |
Shape'e birkaç sınıf metodu ekleyelim.
class Shape def Shape.triangle(sideLength) Shape.new(3, sideLength*3) end def Shape.square(sideLength) Shape.new(4, sideLength*4) end end |
initializeher zaman özeldir).
public,protected ve private
fonksiyonlarından birini kullanarak modül tanımlamaları yardımıyla yapabilirsiniz. Her bir fonksiyon iki farklı amaç
için kullanılabilir.
Eğer hiç argüman olmadan kullanılırsa, üç fonksiyon da daha sonra tanımlanan metotlara varsayılan erişim
kontrolünü atar. Eğer bir C++ ya da Java programcısıysanız, aynı etkiyi gerçekleştirmek için public
kullanmanız size tanıdık gelecektir.
class MyClass def method1 # default is 'public' #... end protected # subsequent methods will be 'protected' def method2 # will be 'protected' #... end private # subsequent methods will be 'private' def method3 # will be 'private' #... end public # subsequent methods will be 'public' def method4 # and this will be 'public' #... end end |
class MyClass def method1 end # ... and so on public :method1, :method4 protected :method2 private :method3 end |
initialize metodu otomatik olarak private olarak tanımlanmıştır.
Şimdi bir kaç örnek görme zamanı. Örneğin, hesaptan düşen paraları kredi olarak sayan bir muhasebe
sistemi tasarladığımızı düşünelim. Bu kuralı kimsenin bozmasını istemediğimiz için, para üstlerini ve kredileri
private olarak tanımladık ve artık işlem terimleri dahilinde dış arayüzümüzü tasarlayacağız.
class Accounts private def debit(account, amount) account.balance -= amount end def credit(account, amount) account.balance += amount end public #... def transferToSavings(amount) debit(@checking, amount) credit(@savings, amount) end #... end |
Account'a, yeni bakiyelerini karşılaştırmak için izin vermek isteyebiliriz,
ancak bu bakiyeleri dünyanın geri kalanından da saklamak istiyoruz (muhtemelen bunları başka bir formda sunmak istediğimiz için).
class Account attr_reader :balance # accessor method 'balance' protected :balance # and make it protected def greaterBalanceThan(other) return @balance > other.balance end end |
balance niteliği korumalı olduğu için, yalnızca Account nesneleri içinden erişilebilir.
| Figure not available... |
person = "Tim"
|
||
person.id
|
» |
537771100
|
person.type
|
» |
String
|
person
|
» |
"Tim"
|
String nesnesi yaratır. Bu nesneye olan referans
yerel değişken person içinde tutulur. Hızlı bir kontrolle, bir nesne id'si, bir tip ve bir değerle
birlikte, gerçekten bir dizginin karakteristiğini aldığını görüyoruz.
Peki, bir değişken bir nesne midir?
Ruby'de cevap ``hayır'' olacaktır. Bir değişken, basitçe bir nesneye bir referanstır. Nesneler
bir yerlerdeki (çoğu zaman yığında (heap) ) büyük bir havuzda yüzerler ve
değişkenler tarafından işaret edilirler.
Şimdi örneğimizi biraz daha karışık hale getirelim.
person1 = "Tim"
|
||
person2 = person1
|
||
|
||
person1[0] = 'J'
|
||
|
||
person1
|
» |
"Jim"
|
person2
|
» |
"Jim"
|
person1'in ilk karakterini değiştirdik, ancak hem person1 hem de
person2, ``Tim'''den ``Jim'''e dönüştü.
Bu durum, bize değişkenlerin nesnelerin kendilerini değil, referanslarını tuttukları gerçeğine geri götürdü.
person1'den person2 atamasıyla yeni bir nesne yaratılmaz; basitçe
person1'in nesne referansı person2'ninkine kopyalanır, böylece
hem person1 hem de person2 aynı nesneyi referans ederler. Bu durumu, sayfa 31'de Şekil 1.3'de gösterdik.
Atama, nesnelere takma ad vermek gibidir, potansiyel olarak, aynı nesneye birden fazla
değişkenle referans edebilirsiniz. Ancak bu durum kodunuzda problemlere yol açmaz mı? Evet, bazı problemler
doğurabilir ancak tahmin ettiğiniz kadar sık değil (örneğin Java'daki nesneler aynı yolla çalışırlar).
Örnek olarak, 3.1'deki örnekte, aynı içerikte yeni bir String nesnesi yaratmaya yarayan String'in dup metodunu kullanarak, takma isim vermeyi
engellemiş oluyorsunuz.
person1 = "Tim"
|
||
person2 = person1.dup
|
||
person1[0] = "J"
|
||
person1
|
» |
"Jim"
|
person2
|
» |
"Tim"
|
TypeError
istisnası vermesine neden olacaktır.
person1 = "Tim" person2 = person1 person1.freeze # prevent modifications to the object person2[0] = "J" |
prog.rb:4:in `=': can't modify frozen string (TypeError) from prog.rb:4 |
| Previous < |
Contents ^
|
Next >
|