@@ -16,13 +16,6 @@ duralım. Rust dilinde birçok smart pointer vardır. Box, RefCell, Rc, Arc gibi
1616 - ** Deref** ve ** Drop** trait’lerini implemente eden struct türleri olarak tasarlanabilirler _ (Yani kendi Smart
1717 Pointer modellerimizi tasarlayabiliriz)_
1818
19- ## Hangisi ne zaman?
20-
21- ** Box** ve ** RefCell** birden fazla sahipliği tek bir veri üzerinde sağlarken, Rc aynı veri üzerinden birden fazla
22- sahiplik sunar. Box immutable veya mutable ödünç alma _ (borrowing)_ için derleme zamanında kontrol sağlar. Rc sadece
23- immutable borrowing için derleme zamanında kontrol sağlar.RefCell immutable veya mutable ödünç alma için runtime'da
24- kontrol sağlar.
25-
2619## Boxing
2720
2821Bir veriyi Stack yerine Heap üzerinde konuşlandırmanın en basit hali Box enstrümanını kullanmaktır. Aşağıda bu kullanıma
@@ -122,4 +115,227 @@ pub fn recursive_sample() {
122115}
123116```
124117
125- // DEVAM EDECEK
118+ Server isimli enum türünün Node alanı içerisinde Box edilen kendi türleri tutulmakta. Burada Box işlemi söz konusu
119+ olduğu için bağlı liste Heap üzerinde konuşlandırılacak.
120+
121+ # Reference Counting
122+
123+ Bilinçli bir şekilde Heap üzerine alınan verilerde birden fazla sahipliğin söz konusu olduğu durumlarda referans
124+ değerlerin sayımı tutulur. Eğer paylaşımlı thread'ler söz konusu değilse Rc türü ihtiyacı karşılar. Birden fazla thread
125+ aynı veri alanı üzerinde çalışma gerektiği durumlarda ise tip güvenliğini gözeten Atomic Reference Counting yani Arc
126+ kullanılır. Aşağıdaki kod parçasında en basit haliyle Rc türünden bir smart pointer kullanımı işlenmektedir.
127+
128+ ``` rust
129+ use std :: rc :: Rc ;
130+
131+ fn main () {
132+ hello_rc ()
133+ }
134+
135+ pub fn hello_rc () {
136+ let p1 = Rc :: new (String :: from (" Some values on the heap" ));
137+ let p2 = p1 . clone ();
138+ let p3 = p2 . clone ();
139+
140+ println! (" p1={:?}" , p1 );
141+ println! (" p2={:?}" , p2 );
142+ println! (" p3={:?}" , p3 );
143+ }
144+ ```
145+
146+ Bu örnekte yer alan p1, p2 ve p3 değişkenleri aynı string veriyi içeren işaretçilerdir. Rc türüne olan ihtiyacı daha iyi
147+ anlamak için aşağıdaki basit örneğe bakalım.
148+
149+ ``` rust
150+ fn main () {
151+ run_rc_with_error ()
152+ }
153+
154+ #[derive(Debug )]
155+ struct Player {
156+ id : u32 ,
157+ name : String ,
158+ friends : Vec <Player >,
159+ }
160+
161+ impl Player {
162+ fn new (id : u32 , name : & str ) -> Self {
163+ Player {
164+ id ,
165+ name : name . to_string (),
166+ friends : Vec :: new (),
167+ }
168+ }
169+
170+ fn add_friend (& mut self , friend : Player ) {
171+ self . friends. push (friend );
172+ }
173+
174+ fn print (& self ) {
175+ println! (" {}'s friends:" , self . name);
176+ for friend in & self . friends {
177+ println! (" {} (ID: {})" , friend . name, friend . id);
178+ }
179+ }
180+ }
181+
182+ pub fn run_rc_with_error () {
183+ let mut steve = Player :: new (1 , " Stivi Vondır" );
184+ let lord = Player :: new (2 , " Lord veyda" );
185+ let anakin = Player :: new (3 , " Anakin" );
186+
187+ steve . add_friend (lord ); // lord' un sahipliği add_friend sonrası steve' e taşındı
188+ steve . add_friend (anakin );
189+
190+ steve . print ();
191+
192+ println! (" Lord veyda's ID: {}" , lord . id); // Value Moved Here
193+ }
194+ ```
195+
196+ Bir oyuncunun arkadaşlarını da yine kendi türünden Vector olarak tutan Player isimli bir veri yapısı mevcut. add_friend
197+ metodu ile bir oyuncuya başka Player örnekleri ekleyebiliyoruz. Player'ın sahip olduğu veri üzerinde değişiklik söz
198+ konusu. Temsili run metoduna baktığımızda son satırdaki println! çağrısında value moved here hatası alırız. Bu son
199+ derece doğaldır zira steve değişkeni üzerinden yapılan ilk add_friend çağrısı sırasında lord değişkeninin sahipliği de
200+ taşınır. Dolayısıyla add_friend sonrası lord değişkenine tekrardan erişilemez. Bu tip bir senaryoyu yönetmek için Rc
201+ smart pointer kullanılabilir. Ancak mutable olma zorunluluğuna dikkat etmek gerekir. Bunu daha iyi anlamak için örneği
202+ aşağıdaki haliyle değiştirelim.
203+
204+ ``` rust
205+ #[derive(Debug )]
206+ struct Player {
207+ id : u32 ,
208+ name : String ,
209+ friends : Vec <Rc <Player >>,
210+ }
211+
212+ impl Player {
213+ fn new (id : u32 , name : & str ) -> Rc <Self > {
214+ Rc :: new (Player {
215+ id ,
216+ name : name . to_string (),
217+ friends : Vec :: new (),
218+ })
219+ }
220+
221+ fn add_friend (self : & Rc <Self >, friend : Rc <Player >) {
222+ self . friends. push (friend );
223+ }
224+
225+ fn print (& self ) {
226+ println! (" {}'s friends:" , self . name);
227+ for friend in self . friends. iter () {
228+ println! (" {} (ID: {})" , friend . name, friend . id);
229+ }
230+ }
231+ }
232+
233+ pub fn run_rc_with_error_2 () {
234+ let steve = Player :: new (1 , " Stivi Vondır" );
235+ let lord = Player :: new (2 , " Lord veyda" );
236+ let anakin = Player :: new (3 , " Anakin" );
237+
238+ steve . add_friend (Rc :: clone (& lord ));
239+ steve . add_friend (Rc :: clone (& anakin ));
240+
241+ steve . print ();
242+
243+ println! (" Lord Veyda's ID: {}" , lord . id);
244+ }
245+ ```
246+
247+ Bu sefer add_friend metodu içerisindeki self.friends.push metodunda bir hata alınır.
248+
249+ ``` text
250+ cannot borrow data in an `Rc` as mutable [E0596]
251+ cannot borrow as mutable
252+ Help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Player>`
253+ ```
254+
255+ Player veri yapısı kendi içerisinden kendi türünden bir Vector kullanmaktadır.İlk hata sebebiyle Vec'ün Rc<Player >
256+ şeklinde kullanılması tercih edilebilir. Ancak bu özellikle add_friends metodunda vektör içeriğine mutable erişmeyi
257+ gerektirir. Bu nedenle vektöre referansının da mutable olarak ele alınabilmesi gerekir. Normalde bir veriye erişen
258+ birden fazla sahip varken mutable kullanım derleme hatasına yol açabilir. ** RefCell** smart pointer kullanımı ile bunu
259+ çalışma zamanına taşırız. Yani ownership kontrolünü runtime tarafında işletilmesini sağlarız. Dolayısıyla örnek kodları
260+ aşağıdaki şekilde değiştirerek ilerleyebiliriz.
261+
262+ ``` rust
263+ use std :: cell :: RefCell ;
264+ use std :: rc :: Rc ;
265+
266+ fn main () {
267+ run_rc ()
268+ }
269+
270+ #[derive(Debug )]
271+ struct Player {
272+ id : u32 ,
273+ name : String ,
274+ friends : RefCell <Vec <Rc <Player >>>,
275+ }
276+
277+ impl Player {
278+ fn new (id : u32 , name : & str ) -> Rc <Self > {
279+ Rc :: new (Player {
280+ id ,
281+ name : name . to_string (),
282+ friends : RefCell :: new (Vec :: new ()),
283+ })
284+ }
285+
286+ fn add_friend (self : & Rc <Self >, friend : Rc <Player >) {
287+ self . friends. borrow_mut (). push (friend );
288+ }
289+
290+ fn print (& self ) {
291+ println! (" {}'s friends:" , self . name);
292+ for friend in self . friends. borrow (). iter () {
293+ println! (" {} (ID: {})" , friend . name, friend . id);
294+ }
295+ }
296+ }
297+
298+ pub fn run_rc () {
299+ let steve = Player :: new (1 , " Stivi Vondır" );
300+ let lord = Player :: new (2 , " Lord veyda" );
301+ let anakin = Player :: new (3 , " Anakin" );
302+
303+ steve . add_friend (Rc :: clone (& lord ));
304+ steve . add_friend (Rc :: clone (& anakin ));
305+
306+ steve . print ();
307+
308+ println! (" Lord Veyda's ID: {}" , lord . id);
309+ }
310+ ```
311+
312+ İlk dikkat edilmesi gereken nokta Player veri yapısındaki friends alanının türüdür. Player nesneleri için bir referans
313+ sayacı kullanılırken değiştirilebilir olmasını sağlama işi RefCell ile çalışma zamanına bırakılmıştır. new metodu
314+ içerisinde RefCell nesnesnin nasıl kullanıldığına da dikkat edelim. Ayrıca friends vektörünü üzerinde değişiklik yapmak
315+ üzere kullanacaksak aynen add_friend metodunda olduğu gibi borrow_mut fonksiyonu ile mutable olarak ödünç alınmasını
316+ sağlamalıyız. Eğer sadee okuma amaçlı kullanacaksak bu durumda da borrow metodunu kullanmalıyız.
317+
318+ Bu senaryoya göre farklı kullanım şekilleri de söz konusu olabilir.
319+
320+ - Sadece bir vektör üzerinde çalışılacaksa RefCell<Vec<Player >> kullanımı yeterlidir.
321+ - Vektörün paylaşımı söz konusu ise Rc<RefCell<Vec<Player >>> daha uygun bir çözüm olabilir.
322+ - Hem vektörü hem de içindeki elemanların paylaşışması gerekiyorsa Rc<Vec<RefCell<Player >>>
323+ daha iyi bir çözüm olabilir.
324+
325+ Şunu da unutmamamak gerekir hem Rc hem de RefCell kullanımının çalışma zamanı maliyetleri daha yüksektir _ (Zira referans
326+ sayımı ve mutasyon kontrolleri yapılmaktadır)_
327+
328+ Buraya kadar gördüğümüz Smart Pointer türlerini aşağıdaki grafikle özetleyebiliriz.
329+
330+ ![ Smart Pointers.png] ( smrt_ptrs.png )
331+
332+ ## Atomic Reference Counting
333+
334+ // Thread'lerin işlendiği bölümde ele alınacaktır
335+
336+ ## Hangisi ne zaman?
337+
338+ ** Box** ve ** RefCell** birden fazla sahipliği tek bir veri üzerinde sağlarken, Rc aynı veri üzerinden birden fazla
339+ sahiplik sunar. Box immutable veya mutable ödünç alma _ (borrowing)_ için derleme zamanında kontroller sağlar. Rc sadece
340+ immutable borrowing için derleme zamanında kontrol sağlar. RefCell immutable veya mutable ödünç alma için runtime'da
341+ kontrol sağlar.
0 commit comments