2015-09-10 30 views
7

Git bir harita üyesinin adresini alarak izin vermez:Neden (&) harita üyesinin adresini almayı yasaklıyorsunuz, ancak (&) dilim öğesine izin veriyorsunuz?

// if I do this: 
p := &mm["abc"] 
// Syntax Error - cannot take the address of mm["abc"] 

mantığı git bu adresi alarak verir eğer haritası backstore büyür veya shinks zaman, adres ve kullanıcıyı şaşırtabilir geçersiz hale olmasıdır .

a := make([]Test, 5) 
a[0] = Test{1, "dsfds"} 
a[1] = Test{2, "sdfd"} 
a[2] = Test{3, "dsf"} 

addr1 := reflect.ValueOf(&a[2]).Pointer() 
fmt.Println("Address of a[2]: ", addr1) 

a = append(a, Test{4, "ssdf"}) 
addrx := reflect.ValueOf(&a[2]).Pointer() 
fmt.Println("Address of a[2] After Append:", addrx) 

// Note after append, the first address is invalid 
Address of a[2]: 833358258224 
Address of a[2] After Append: 833358266416 

Geçiş Neden böyle tasarlanmıştır:

Ama git dilim onun kapasitesini içinde büyüyor, henüz Git bir dilim elemanının adresini almamızı izin verdiğinde taşındı alır? Dilim elemanının adresinin alınmasıyla ilgili özel olan nedir?

+3

Bunu okuyun: [Git: Diziler ve haritalar farklı kavramlar/özellikler mi olmalı?] (Http://stackoverflow.com/questions/25294290/go-do-arrays-and-maps-have-to-be -farklı-kavramlar-özellikler – icza

+2

Ne yazık ki, bir dilim öğesinin adresini alma konusunda hiçbir şey özel değildir - eğer dilim büyüdükten sonra bu ilk adresi kullanmaya devam ederseniz ('kodunu çalıştırmak yerine '& a [2]' yeniden post-' append ', yaptığınız gibi, hala eski diziye işaretçiniz olacak, böylece yeni diziyi görmek veya güncellemek için kullanamazsınız, ve eski diziye hala ulaşılabilir ve çöp değil - koleksiyon. Harita için – twotwotwo

+0

düzeltme adresi dizisi için adres sabitleme daha zor olduğunu düşünüyorum. –

cevap

10

dilimleri ve haritalar arasında büyük bir fark vardır: Dilimler bir destek dizisi tarafından desteklenen ve haritalar değildir.

harita büyür ya da hiçbir yerde (başlatılmamış belleğe) içine sarkan işaretçi işaret olabilir bir harita öğesine bir potansiyel işaretçi küçülür edin. Buradaki sorun "kullanıcının kafası karışıklığı" değil, Go'nun önemli bir tasarım unsurunu kırmasıdır: Sarkma işaretçilerinin olmaması.

bir dilim daha büyük bir destek dizisi oluşturulur ve eski destek dizisi yeni kopyalandığını, kapasite yeni biterse

; ve eski destek dizisi , mevcut . Böylece, eski destek dizisine işaret eden "ungrown" dilimden elde edilen herhangi bir işaretçi, geçerli bellek için hala geçerli işaretçilerdir.

Eğer hala eski destek dizisine erişmek (eğer kapasitesinin ötesinde dilim büyüyen önce dilim bir kopyasını yaptı çünkü örneğin) bir dilim hala eski destek diziye işaret varsa. Bu, dilim öğelerinin işaretçileriyle daha az ilgisi vardır; ancak dilimler, diziler halinde görünümler ve dilim büyümesi sırasında kopyalanan dizilerdir.

vardır Not hiçbir dilim büzüşme sırasında "bir dilimin destek dizisi azaltılması".

+0

Teşekkürler! Yapı alanları nasıl? Bunun gibi bir alanın adresini alabilirim: 'ptr: = & (object.Field1)', ama adresi yansıtarak almayı denediğimde, 'CanAddr()' false döndürür: ben reflect.ValueOf denedim (object) .FieldByName ("Field1"). CanAddr() 've' reflect.ValueOf (& object) .Elem(). FieldByName ("Field1"). CanAddr() ', her ikisi de false döndürür. Niye ya? – NeoWang

+1

@NeoWang: yansıtacak nesnenin değerini geçtiğiniz için. Hala anlamadığınız başka bir soru sorabilirsiniz; Haritalar veya dilimlerle alakalı değil. – JimB