-
Notifications
You must be signed in to change notification settings - Fork 6
/
choosing-your-guarantees.html
629 lines (541 loc) · 32.4 KB
/
choosing-your-guarantees.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="rustdoc">
<title>Scegliere le proprie garanzie</title>
<link rel="stylesheet" type="text/css" href="rustbook.css">
</head>
<body class="rustdoc">
<!--[if lte IE 8]>
<div class="warning">
This old browser is unsupported and will most likely display funky
things.
</div>
<![endif]-->
<div id="nav">
<button id="toggle-nav">
<span class="sr-only">Toggle navigation</span>
<span class="bar"></span>
<span class="bar"></span>
<span class="bar"></span>
</button>
</div>
<div id='toc' class='mobile-hidden'>
<ul class='chapter'>
<li><a href='README.html'><b>1.</b> Introduzione</a>
</li>
<li><a href='getting-started.html'><b>2.</b> Come Iniziare</a>
</li>
<li><a href='guessing-game.html'><b>3.</b> Tutorial: Gioco-indovina</a>
</li>
<li><a href='syntax-and-semantics.html'><b>4.</b> Sintassi e semantica</a>
<ul class='section'>
<li><a href='variable-bindings.html'><b>4.1.</b> Legami di variabili</a>
</li>
<li><a href='functions.html'><b>4.2.</b> Funzioni</a>
</li>
<li><a href='primitive-types.html'><b>4.3.</b> Tipi primitivi</a>
</li>
<li><a href='comments.html'><b>4.4.</b> Commenti</a>
</li>
<li><a href='if.html'><b>4.5.</b> if</a>
</li>
<li><a href='loops.html'><b>4.6.</b> Cicli</a>
</li>
<li><a href='vectors.html'><b>4.7.</b> Vettori</a>
</li>
<li><a href='ownership.html'><b>4.8.</b> Possesso</a>
</li>
<li><a href='references-and-borrowing.html'><b>4.9.</b> Riferimenti e prestito</a>
</li>
<li><a href='lifetimes.html'><b>4.10.</b> Tempo di vita</a>
</li>
<li><a href='mutability.html'><b>4.11.</b> Mutabilità</a>
</li>
<li><a href='structs.html'><b>4.12.</b> Strutture</a>
</li>
<li><a href='enums.html'><b>4.13.</b> Enumerazioni</a>
</li>
<li><a href='match.html'><b>4.14.</b> Match</a>
</li>
<li><a href='patterns.html'><b>4.15.</b> Pattern</a>
</li>
<li><a href='method-syntax.html'><b>4.16.</b> Sintassi dei metodi</a>
</li>
<li><a href='strings.html'><b>4.17.</b> Stringhe</a>
</li>
<li><a href='generics.html'><b>4.18.</b> Genericità</a>
</li>
<li><a href='traits.html'><b>4.19.</b> Tratti</a>
</li>
<li><a href='drop.html'><b>4.20.</b> Drop</a>
</li>
<li><a href='if-let.html'><b>4.21.</b> `if let`</a>
</li>
<li><a href='trait-objects.html'><b>4.22.</b> Oggetti-tratti</a>
</li>
<li><a href='closures.html'><b>4.23.</b> Chiusure</a>
</li>
<li><a href='ufcs.html'><b>4.24.</b> Sintassi universale di chiamata di funzione</a>
</li>
<li><a href='crates-and-modules.html'><b>4.25.</b> Crate e moduli</a>
</li>
<li><a href='const-and-static.html'><b>4.26.</b> `const` e `static`</a>
</li>
<li><a href='attributes.html'><b>4.27.</b> Attributi</a>
</li>
<li><a href='type-aliases.html'><b>4.28.</b> Alias tramite `type`</a>
</li>
<li><a href='casting-between-types.html'><b>4.29.</b> Forzatura di tipo</a>
</li>
<li><a href='associated-types.html'><b>4.30.</b> Tipi associati</a>
</li>
<li><a href='unsized-types.html'><b>4.31.</b> Tipi non dimensionati</a>
</li>
<li><a href='operators-and-overloading.html'><b>4.32.</b> Operatori e sovraccaricamento</a>
</li>
<li><a href='deref-coercions.html'><b>4.33.</b> Coercizione Deref</a>
</li>
<li><a href='macros.html'><b>4.34.</b> Le macro</a>
</li>
<li><a href='raw-pointers.html'><b>4.35.</b> Puntatori grezzi</a>
</li>
<li><a href='unsafe.html'><b>4.36.</b> `unsafe`</a>
</li>
</ul>
</li>
<li><a href='effective-rust.html'><b>5.</b> Rust efficace</a>
<ul class='section'>
<li><a href='the-stack-and-the-heap.html'><b>5.1.</b> Lo stack e lo heap</a>
</li>
<li><a href='testing.html'><b>5.2.</b> Collaudo</a>
</li>
<li><a href='conditional-compilation.html'><b>5.3.</b> Compilazione condizionale</a>
</li>
<li><a href='documentation.html'><b>5.4.</b> Documentazione</a>
</li>
<li><a href='iterators.html'><b>5.5.</b> Iteratori</a>
</li>
<li><a href='concurrency.html'><b>5.6.</b> Concorrenza</a>
</li>
<li><a href='error-handling.html'><b>5.7.</b> Gestione degli errori</a>
</li>
<li><a class='active' href='choosing-your-guarantees.html'><b>5.8.</b> Scegliere le garanzie</a>
</li>
<li><a href='ffi.html'><b>5.9.</b> FFI</a>
</li>
<li><a href='borrow-and-asref.html'><b>5.10.</b> Prestito e AsRef</a>
</li>
<li><a href='release-channels.html'><b>5.11.</b> Canali di rilascio</a>
</li>
<li><a href='using-rust-without-the-standard-library.html'><b>5.12.</b> Usare Rust senza la libreria standard</a>
</li>
</ul>
</li>
<li><a href='nightly-rust.html'><b>6.</b> Rust notturno</a>
<ul class='section'>
<li><a href='compiler-plugins.html'><b>6.1.</b> Plugin del compilatore</a>
</li>
<li><a href='inline-assembly.html'><b>6.2.</b> Assembly in-line</a>
</li>
<li><a href='no-stdlib.html'><b>6.3.</b> Omettere la libreria stdandard</a>
</li>
<li><a href='intrinsics.html'><b>6.4.</b> Intrinseci</a>
</li>
<li><a href='lang-items.html'><b>6.5.</b> Elementi "lang"</a>
</li>
<li><a href='advanced-linking.html'><b>6.6.</b> Link avanzato</a>
</li>
<li><a href='benchmark-tests.html'><b>6.7.</b> Collaudi prestazionali</a>
</li>
<li><a href='box-syntax-and-patterns.html'><b>6.8.</b> Sintassi di box e relativi pattern</a>
</li>
<li><a href='slice-patterns.html'><b>6.9.</b> Pattern di slice</a>
</li>
<li><a href='associated-constants.html'><b>6.10.</b> Costanti associate</a>
</li>
<li><a href='custom-allocators.html'><b>6.11.</b> Allocatori personalizzati</a>
</li>
</ul>
</li>
<li><a href='glossary.html'><b>7.</b> Glossario</a>
</li>
<li><a href='syntax-index.html'><b>8.</b> Indice analitico della sintassi</a>
</li>
</ul>
</div>
<div id='page-wrapper'>
<div id='page'>
<h1 class="title">Scegliere le proprie garanzie</h1>
<p>Una caratteristica importante di Rust è che permette di controllare i costi
e le garanzie del proprio programma.</p>
<p>Ci sono varie astrazioni "di tipo wrapper" nella libreria standard di Rust
che impersonano una moltitudine di pro e contro riguardo il costo, l'ergonomia,
e le garanzie. Molte permettono di scegliere se applicare le garanzie in fase
di compilazione o in fase di esecuzione. Questa sezione spiega in dettaglio
alcune astrazioni selezionate.</p>
<p>Prima di procedere, è fortemente consigliato aver letto le sezioni
sul <a href="ownership.html">possesso</a> e sui <a href="references-and-borrowing.html">prestiti</a> in Rust.</p>
<h1 id='i-tipi-puntatori-di-base' class='section-header'><a href='#i-tipi-puntatori-di-base'>I tipi puntatori di base</a></h1>
<h2 id='boxt' class='section-header'><a href='#boxt'><code>Box<T></code></a></h2>
<p><a href="../std/boxed/struct.Box.html"><code>Box<T></code></a> è un puntatore "posseduto", ossia un "box". Mentre può fornire
riferimenti ai dati contenuti, è l'unico possessore dei dati. In particolare,
di consideri questo:</p>
<span class='rusttest'>fn main() {
let x = Box::new(1);
let y = x;
// qui x non è più accessibile
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>x</span> <span class='op'>=</span> <span class='ident'>Box</span>::<span class='ident'>new</span>(<span class='number'>1</span>);
<span class='kw'>let</span> <span class='ident'>y</span> <span class='op'>=</span> <span class='ident'>x</span>;
<span class='comment'>// qui x non è più accessibile</span></pre>
<p>Qui, il box è stato <em>spostato</em> in <code>y</code>. Siccome <code>x</code> non lo possiede più,
dopo di ciò il compilatore non consentirà più al programmatore di usare <code>x</code>.
Analogamente, un box può essere spostato <em>fuori</em> da una funzione
restituendolo.</p>
<p>Quando un box (che non è stato spostato) esce di ambito, vengono eseguiti
i distruttori. Questi distruttori hanno cura di deallocare i dati interni.</p>
<p>Questa è un'astrazione a costo zero per l'allocazione dinamica.
se si vuole allocare della memoria dallo heap e mandare in giro in sicurezza
un puntatore a tale memoria, "box" è l'ideale. Si noti che verrà consentito
condividere riferimenti a questo oggetto solamente tramite le normali
regole di prestito, verificate in fase di compilazione.</p>
<h2 id='t-e-mut-t' class='section-header'><a href='#t-e-mut-t'><code>&T</code> e <code>&mut T</code></a></h2>
<p>Questi sono, rispettivamente, un riferimento immutabile e
un riferimento mutabile. Seguono il pattern "lock di lettura-scrittura",
tale che si può o avere un solo riferimento mutabile ad alcuni dati,
o qualunque numero di riferimenti immutabile, ma non entrambi. Questa garanzia
è applicata in fase di compilazione, e non ha costi visibili
in fase di esecuzione. Nella maggior parte dei casi, questi due tipi
di puntatori bastando per condividere riferimenti poco costosi fra sezioni
di codice.</p>
<p>Questi puntatori non possono essere copiati in modo tale da sopravvivere
il tempo di vita associato ad essi.</p>
<h2 id='const-t-e-mut-t' class='section-header'><a href='#const-t-e-mut-t'><code>*const T</code> e <code>*mut T</code></a></h2>
<p>Questi sono puntatori grezzi tipo-C, senza tempo di vita né possesso allegati.
Puntano ad alcune posizioni in memoria senza altre restrizioni. L'unica
garanzia che forniscono è che non possono essere dereferenziati eccetto
nel codice marcato <code>unsafe</code>.</p>
<p>Servono per costruire astrazioni sicure e a basso costo, come <code>Vec<T></code>,
ma dovrebbero essere evitati nel codice sicuro.</p>
<h2 id='rct' class='section-header'><a href='#rct'><code>Rc<T></code></a></h2>
<p>Questo è il primo wrapper che tratteremo che ha un costo in fase di esecuzione.</p>
<p><a href="../std/rc/struct.Rc.html"><code>Rc<T></code></a> è un puntatore a conteggio di riferimenti. In altri termini,
consente di avere più puntatori "possessori" allo stesso dato, e il dato
verrà rilasciato (con l'esecuzione dei distruttori) quando tutti i puntatori
usciranno di ambito.</p>
<p>Internamente, contiene una "conteggio di riferimenti" condiviso (chiamato
anche "refcount"), che viene incrementato ogni volta che l'<code>Rc</code> viene clonato,
e decrementato ogni volta che uno degli <code>Rc</code> esce di ambito. La responsabilità
principale di <code>Rc<T></code> è assicurarsi che siano chiamati i distruttori per
il dato condiviso.</p>
<p>Qui i dati interni sono immutabili, e se viene creato un ciclo
di riferimenti, i dati rimarranno sempre allocati ("leak").
Se vogliamo dei dati che potranno essere deallocati anche in presenza
di strutture cicliche, ci serve un garbage collector.</p>
<h3 id='garanzie' class='section-header'><a href='#garanzie'>Garanzie</a></h3>
<p>La garanzia principale fornita qui è che i dati non saranno distrutti
finché tutti i riferimenti ad essi escano di ambito.</p>
<p>Questo si dovrebbe essere usato quando desideriamo allocare dinamicamente
e condividere dei dati (a sola lettura) fra varie porzioni del programma,
nel quale non è certo quale porzione finirà per ultima di usare tali dati.
È un'alternativa praticable a <code>&T</code>, quando o è impossibile verificare
staticamente la correttezza di <code>&T</code>, o usando <code>&T</code> si crea del codice
estremamente non ergonomico, per il quale non vale la pena investire
il tempo del programmatore.</p>
<p>Questo puntatore <em>non</em> è sicuro per l'uso coi thread, e Rust non lo lascerà
inviare o condividere con altri thread. Ciò consente di evitare il costo
delle operazioni atomiche dove non sono necessarie.</p>
<p>C'è uno smart pointer fratello di questo, <code>Weak<T></code>. Questo è
uno smart pointer che non possiede, ma non è neanche preso in prestito.
Anch'esso è simile a <code>&T</code>, ma non ha un tempo di vita limitato: un <code>Weak<T></code>
può essere tenuto per sempre. Però, è possibile che un tentativo di accedere
al dato interno fallisca e restituisca <code>None</code>, dato che può sopravvivere
gli <code>Rc</code> che possiedono il dato. Ciò è utile, tra l'altro, per creare
strutture dati cicliche.</p>
<h3 id='costo' class='section-header'><a href='#costo'>Costo</a></h3>
<p>Per quanto riguarda la memoria, <code>Rc<T></code> è un'allocazione singola,
però allocherà due word in più (cioè due valori <code>usize</code>) rispetto
a un normale <code>Box<T></code> (questo vale anche per i <code>Weak</code>).</p>
<p><code>Rc<T></code> ha il costo computazionale di incrementare/decrementare il conteggio,
rispettivamente ogni volta che viene clonato o che esce di ambito. Si noti
che un <code>clone</code> non farà una copia profonda, ma incrementerà semplicemente
il conteggio interno di riferimenti e restituirà una copia del <code>Rc<T></code>.</p>
<h1 id='i-tipi-cell' class='section-header'><a href='#i-tipi-cell'>I tipi Cell</a></h1>
<p>I <code>Cell</code> forniscono la mutabilità interna. In altri termini, contengono
dei dati che possono essere manipolati anche se il tipo non può
essere ottenuto in una forma mutabile (per esempio, quando è dietro
un puntatore <code>&</code>, oppure un <code>Rc<T></code>).</p>
<p><a href="../std/cell/index.html">La documentazione del modulo <code>cell</code> li spiega molto bene</a>.</p>
<p>Questi tipo <em>solitamente</em> si trovano nei campi di struct, ma si possono
trovare anche altrove.</p>
<h2 id='cellt' class='section-header'><a href='#cellt'><code>Cell<T></code></a></h2>
<p><a href="../std/cell/struct.Cell.html"><code>Cell<T></code></a> è un tipo che fornisce mutabilità interna a costo zero,
ma solamente per tipi <code>Copy</code>. Dato che il compilatore sa che tutti i dati
posseduto dal valore contenuto stanno sono sullo stack, non c'è il rischio
che la semplice sovrascrittura dei dati comporti mancate disallocazioni
di riferimenti (o peggio!).</p>
<p>Usando questo wrapper, è ancora possibile violare le proprie invarianti,
e quindi bisogna essere cauti nell'usarlo. Se un campo è contenuto
in un <code>Cell</code>, è una chiara indicazione che quel dato è mutabile e potrebbe
non rimanere invariato tra quando lo si legge e quando lo si vuole usare.</p>
<span class='rusttest'>fn main() {
use std::cell::Cell;
let x = Cell::new(1);
let y = &x;
let z = &x;
x.set(2);
y.set(3);
z.set(4);
println!("{}", x.get());
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>use</span> <span class='ident'>std</span>::<span class='ident'>cell</span>::<span class='ident'>Cell</span>;
<span class='kw'>let</span> <span class='ident'>x</span> <span class='op'>=</span> <span class='ident'>Cell</span>::<span class='ident'>new</span>(<span class='number'>1</span>);
<span class='kw'>let</span> <span class='ident'>y</span> <span class='op'>=</span> <span class='kw-2'>&</span><span class='ident'>x</span>;
<span class='kw'>let</span> <span class='ident'>z</span> <span class='op'>=</span> <span class='kw-2'>&</span><span class='ident'>x</span>;
<span class='ident'>x</span>.<span class='ident'>set</span>(<span class='number'>2</span>);
<span class='ident'>y</span>.<span class='ident'>set</span>(<span class='number'>3</span>);
<span class='ident'>z</span>.<span class='ident'>set</span>(<span class='number'>4</span>);
<span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>x</span>.<span class='ident'>get</span>());</pre>
<p>Si noti che qui abbiamo potuto mutare il medesimo oggetto da vari
riferimenti immutabili.</p>
<p>Questo ha lo stesso costo in fase di esecuzione del seguente:</p>
<span class='rusttest'>fn main() {
let mut x = 1;
let y = &mut x;
let z = &mut x;
x = 2;
*y = 3;
*z = 4;
println!("{}", x);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>x</span> <span class='op'>=</span> <span class='number'>1</span>;
<span class='kw'>let</span> <span class='ident'>y</span> <span class='op'>=</span> <span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='ident'>x</span>;
<span class='kw'>let</span> <span class='ident'>z</span> <span class='op'>=</span> <span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='ident'>x</span>;
<span class='ident'>x</span> <span class='op'>=</span> <span class='number'>2</span>;
<span class='op'>*</span><span class='ident'>y</span> <span class='op'>=</span> <span class='number'>3</span>;
<span class='op'>*</span><span class='ident'>z</span> <span class='op'>=</span> <span class='number'>4</span>;
<span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{}"</span>, <span class='ident'>x</span>);</pre>
<p>ma ha il beneficio non trascurabile di poter essere compilato.</p>
<h3 id='garanzie-1' class='section-header'><a href='#garanzie-1'>Garanzie</a></h3>
<p>Questo allenta la restrizione del "nessun alias con la mutabilità" dove
non è necessaria. Però, questo allenta che le garanzie fornite
da tale restrizione; quindi se i propri invarianti dipendono da dati
memorizzati in un <code>Cell</code>, si dovrebbe essere cauti.</p>
<p>Ciò è utile per tipi primitivi mutabili e altri tipi <code>Copy</code>, quando
non ci sono modi facili di farlo conformemente alle regole statiche
di <code>&</code> e di <code>&mut</code>.</p>
<p><code>Cell</code> non consente di ottenere riferimenti al dato interno, il che rende
sicuro mutarlo liberamente.</p>
<h4 id='costo-1' class='section-header'><a href='#costo-1'>Costo</a></h4>
<p>Non ci sono costi in fase di esecuzione a usare <code>Cell<T></code>, però se lo
si sta usando per avvolgere struct (<code>Copy</code>) più grandi, potrebbe invece
essere opportuno avvolgere i singoli campi in <code>Cell<T></code> dato che altrimenti
ogni scrittura copia l'intera struct.</p>
<h2 id='refcellt' class='section-header'><a href='#refcellt'><code>RefCell<T></code></a></h2>
<p>Anche <a href="../std/cell/struct.RefCell.html"><code>RefCell<T></code></a> fornisce mutabilità interna, ma non è limitata
ai tipi <code>Copy</code>.</p>
<p>In compenso, ha un costo in fase di esecuzione. <code>RefCell<T></code> impone in fase
di esecuzione il pattern del lock di lettura-scrittura (è come un mutex
a sngolo thread), diversamente da <code>&T</code>/<code>&mut T</code> che lo fanno in fase
di compilazione. Ciò viene fatto dalle funzioni <code>borrow()</code> e <code>borrow_mut()</code>,
che modificano un conteggio di riferimenti interno e restituiscono degli
smart pointers che possono essere dereferenziati, rispettivamente in modo
immutabile e mutabile. Il refcount viene ripristinato quando
gli smart pointer escono di ambito. Con questo sistema, possiamo assicurare
dinamicamente che non ci sono mai altri prestiti attivi quando un prestito
mutabile è attivo. Se il programmatore tenta di eseguire un tale prestito,
il thread andrà in panico.</p>
<span class='rusttest'>fn main() {
use std::cell::RefCell;
let x = RefCell::new(vec![1,2,3,4]);
{
println!("{:?}", *x.borrow())
}
{
let mut mio_riferimento = x.borrow_mut();
mio_riferimento.push(1);
}
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>use</span> <span class='ident'>std</span>::<span class='ident'>cell</span>::<span class='ident'>RefCell</span>;
<span class='kw'>let</span> <span class='ident'>x</span> <span class='op'>=</span> <span class='ident'>RefCell</span>::<span class='ident'>new</span>(<span class='macro'>vec</span><span class='macro'>!</span>[<span class='number'>1</span>,<span class='number'>2</span>,<span class='number'>3</span>,<span class='number'>4</span>]);
{
<span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{:?}"</span>, <span class='op'>*</span><span class='ident'>x</span>.<span class='ident'>borrow</span>())
}
{
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>mio_riferimento</span> <span class='op'>=</span> <span class='ident'>x</span>.<span class='ident'>borrow_mut</span>();
<span class='ident'>mio_riferimento</span>.<span class='ident'>push</span>(<span class='number'>1</span>);
}</pre>
<p>Simile a <code>Cell</code>, serve principalmente in situazioni in cui è difficile
o impossibile soddisfare il verificatore dei prestiti. In generale sappiamo
che tali mutazioni non avverranno in una forma annidata, ma è bene verificare.</p>
<p>Per programmi grandi e complicati, diventa utile mettere alcuni oggetti
in <code>RefCell</code> per semplificare le cose. Per esempio, molte delle mappe
nella struct <code>ctxt</code> interna al compilatore Rust sono poste dentro
questo wrapper. Esse vengono modificate o una sola volta (durante
la creazione, che non è subito dopo l'inizializzazione) o un paio di volte
in luoghi bene separati. Però, siccome questa struct è usata dappertutto,
sarebbe difficile (e forse impossibile) destreggiarsi con puntatori mutabili
o immutabili, e probabilmente formare una zuppa di puntatori <code>&</code> che
poi sarebbe difficile estendere. D'altra parte, <code>RefCell</code> fornisce un modo
a basso costo di accedere con sicurezza a queste strutture. In futuro, se
qualcuno aggiungesse del codice che tenta di modificare la cella quando è
già stata prestata, questo provocherà un panico (solitamente deterministico)
che può esser fatto risalire al prestito erroneo.</p>
<p>Similmente, nel DOM di Servo ci sono molte mutazioni, per lo più locali
a un tipo DOM, ma alcune delle quali incrociano il DOM e modificano
varie cose. Usare <code>RefCell</code> e <code>Cell</code> per proteggere tutte le mutazioni
consente di evitare di preoccuparsi ovunque della mutabilità,
e simultaneamente evidenzia i posti dove la mutazione
sta <em>effettivamente</em> avvenendo.</p>
<p>Si noti che <code>RefCell</code> dovrebbe essere evitato se è possibile
una soluzione più semplice utilizzando i puntatori <code>&</code>.</p>
<h3 id='garanzie-2' class='section-header'><a href='#garanzie-2'>Garanzie</a></h3>
<p><code>RefCell</code> allenta le restrizioni <em>statiche</em> che impediscono le mutazioni
tramite alias, e le sostituisce con restrizioni <em>dinamiche</em>.
Però tali garanzie non sono cambiate.</p>
<h4 id='costo-2' class='section-header'><a href='#costo-2'>Costo</a></h4>
<p><code>RefCell</code> non alloca, ma contiene, a fianco del dato, un indicatore
aggiuntivo di "stato di prestito" (grande una word).</p>
<p>In fase di esecuzione, ogni prestito provoca una modifica/verifica
di tale indicatore.</p>
<h1 id='tipi-sincroni' class='section-header'><a href='#tipi-sincroni'>Tipi sincroni</a></h1>
<p>Molti dei tipi di cui si è parlato non possono essere usati in modo sicuro
per l'uso coi thread. In particolare, <code>Rc<T></code> e <code>RefCell<T></code>, entrambi
i quali usano conteggi di riferimenti non atomici (i conteggi
di riferimenti <em>atomici</em> sono quelli che possono essere incrementati da più
thread senza provocare una corsa ai dati), non si possono usare
in questo modo. Ciò li rende più efficienti da usare, ma ci servono anche
delle versioni sicure per l'uso coi thread. Esistono, sotto forma di <code>Arc<T></code>
e di <code>Mutex<T></code>/<code>RwLock<T></code></p>
<p>Si noti che i tipi non sicuri per l'uso coi thread <em>non possono</em> essere
scambiati tra thread, e ciò viene verificato in fase di compilazione.</p>
<p>Nel modulo <a href="../std/sync/index.html">sync</a> ci sono molti utili wrapper per la programmazione
concorrente, ma qui sotto verranno trattati solo i principali.</p>
<h2 id='arct' class='section-header'><a href='#arct'><code>Arc<T></code></a></h2>
<p><a href="../std/sync/struct.Arc.html"><code>Arc<T></code></a> è una versione di <code>Rc<T></code> che usa un conteggio di riferimenti
atomico (da cui il nome, "Arc" = "Atomic Reference Count").
Può essere scambiato liberamente fra thread.</p>
<p>Il tipo <code>shared_ptr</code> del linguaggio C++ è simile ad <code>Arc</code>, però nel caso
di C++ il dato interno è sempre mutabile. Per avere una semantica simile
a quella di <code>shared_ptr</code>, si dovrebbero usare <code>Arc<Mutex<T>></code>,
<code>Arc<RwLock<T>></code>, o <code>Arc<UnsafeCell<T>></code><sup id="fnref1"><a href="#fn1" rel="footnote">1</a></sup> (<code>UnsafeCell<T></code> è un tipo
di cella che può essere usato per tenere qualunque dato e non ha costi
in fase di esecuzione, ma è accessibile solamente da blocchi <code>unsafe</code>).
L'ultimo dovrebbe essere usato solamente se si è certi che l'utilizzo non
provocherà insicurezza nella gestione della memoria. Ricordiamo che
scrivere una struttura non è un'operazione atomica, e moste funzioni
come <code>vec.push()</code> possono riallocare internamente, e provocare
un comportamento insicuro, quindi perfino la monotonicità potrebbe
non bastare per giustificare <code>UnsafeCell</code>.</p>
<p><code>UnsafeCell<T></code> non è <code>Send</code> né <code>Sync</code>, ma possiamo avvolgerlo in un tipo
e implementare manualmente <code>Send</code>/<code>Sync</code> per esso, così da ottenere
<code>Arc<Wrapper<T>></code>, dove <code>Wrapper</code> è <code>struct Wrapper<T>(UnsafeCell<T>)</code>.</p>
<h3 id='garanzie-3' class='section-header'><a href='#garanzie-3'>Garanzie</a></h3>
<p>Come <code>Rc</code>, anche questo tipo fornisce la garanzia (sicura per l'uso
coi thread) che il distruttore per i dati interni verrà eseguito quando
l'ultimo <code>Arc</code> esce di ambito (eccetto in presenza di strutture cicliche).</p>
<h3 id='costo-3' class='section-header'><a href='#costo-3'>Costo</a></h3>
<p>Questo tipo ha il costo aggiuntivo di usare operazioni atomiche per modificare
il refcount (che accadrà ogni volta che è clonato o esce di ambito). Quando
si condividono dati da un <code>Arc</code> in un solo thread, è preferibile condividere
puntatori <code>&</code>, quando è possibile.</p>
<h2 id='mutext-e-rwlockt' class='section-header'><a href='#mutext-e-rwlockt'><code>Mutex<T></code> e <code>RwLock<T></code></a></h2>
<p><a href="../std/sync/struct.Mutex.html"><code>Mutex<T></code></a> e <a href="../std/sync/struct.RwLock.html"><code>RwLock<T></code></a> forniscono la mutua-esclusione
tramite guardie RAII (le guardie sono oggetti che mantengono un certo stato,
come un lock, fino a quando è chiamato il loro distruttore). Per entrambe,
il mutex è opaco finché chiamiamo <code>lock()</code> su di esso. A quel punto il thread
si bloccherà fino a quando si potrà acquisire un lock, e poi verrà
restituita un guardia. Questa guardia può essere usata per accedere
(mutabilmente) al dato interno, e il lock verrà rilasciato quando la guardia
esce di ambito.</p>
<span class='rusttest'>fn main() {
{
let guardia = mutex.lock();
// guardia dereferenzia mutabilmente dando il tipo interno
*guardia += 1;
} // lock rilasciato quando si esegue il distruttore
}</span><pre class='rust rust-example-rendered'>
{
<span class='kw'>let</span> <span class='ident'>guardia</span> <span class='op'>=</span> <span class='ident'>mutex</span>.<span class='ident'>lock</span>();
<span class='comment'>// guardia dereferenzia mutabilmente dando il tipo interno</span>
<span class='op'>*</span><span class='ident'>guardia</span> <span class='op'>+=</span> <span class='number'>1</span>;
} <span class='comment'>// lock rilasciato quando si esegue il distruttore</span></pre>
<p><code>RwLock</code> ha il beneficio aggiuntivo di essere efficiente per più letture.
È sempre sicuro avere più lettori a dati condivisi purché non ci
siano scrittori; e <code>RwLock</code> consente ai lettori di acquisire
un "lock di lettura". Tali lock possono essere acquisiti concorrentemente e
se ne tiene traccia tramite un conteggio di riferimenti.
Gli scrittori devono ottenere un "lock di scrittura" che può essere ottenuto
solamente quando tutti i lettori sono usciti di scope.</p>
<h3 id='garanzie-4' class='section-header'><a href='#garanzie-4'>Garanzie</a></h3>
<p>Entrambi questi tipi forniscono mutabilità sicura condivisa fra thread,
però sono soggetti a deadlock. Qualche livello aggiuntivo di sicurezza
del protocollo può essere ottenuto tramite il sistema dei tipi.</p>
<h3 id='costi' class='section-header'><a href='#costi'>Costi</a></h3>
<p>Questi tipi usano tipi interni di tipo atomico per mantenere i lock,
i quali sono parecchio costosi (possono bloccare tutte le letture in memoria
per tutti i processori fino a quando hanno finito). Anche attendere
questi lock può essere lento quando avvengono molti accessi concorrenti.</p>
<h1 id='composizione' class='section-header'><a href='#composizione'>Composizione</a></h1>
<p>Una tipica lamentela quando si legge del codice Rust è per i tipi come
<code>Rc<RefCell<Vec<T>>></code> (o composizioni ancora più complicate di tali tipi).
Non è sempre chiaro che cosa faccia la composizione, o perché l'autore ne
ha scelta una così (e quando si dovrebbe usare tale composizione
nel proprio codice).</p>
<p>Solitamente, si tratta comporre insieme le garanzie che servono,
senza pagare per quello che non serve.</p>
<p>Per esempio, <code>Rc<RefCell<T>></code> è una tale composizione. <code>Rc<T></code> stesso
non può essere dereferenziato mutabilmente; siccome <code>Rc<T></code> fornisce
la condivisione, e la mutabilità condivisa può condurre a comportamento
insicuro, mettiamo dentro <code>RefCell<T></code> per ottenere mutabilità condivisa
verificata dinamicamente. Adesso abbiamo un dato mutable condiviso,
ma è condiviso in un modo che ci può essere un solo scrittore
(e nessun lettore), oppure più lettori.</p>
<p>Adesso, possiamo fare un passo avanti, e abbiamo <code>Rc<RefCell<Vec<T>>></code> oppure
<code>Rc<Vec<RefCell<T>>></code>. Questi sono entrambi vettori condivisibili e mtabili,
ma non sono la medesima cosa.</p>
<p>Con il primo, il <code>RefCell<T></code> avvolge il <code>Vec<T></code>, e così <code>Vec<T></code>
nella sua interezza è mutabile. Al medesimo tempo, ci può essere
un solo prestito mutabile per volta dell'intero <code>Vec</code>.
Ciò comporta che il nostro codice nn può funzionare simultaneamente
su elementi distinti del vettore da diversi handle <code>Rc</code>. Però, possiamo
eseguire <code>push</code> e <code>pop</code> a volontà con il <code>Vec<T></code>. Ciò è simile
a un <code>&mut Vec<T></code> con i prestiti verificati in fase di esecuzione.</p>
<p>Con l'ultimo, il prestito è di elementi individuali, ma il vettore
complessivo è immutabile. Così, possiamo prendere in prestito
indipendentemente elementi distinti, ma non possiamo eseguire <code>push</code> né <code>pop</code>
con il vettore. Ciò è simile a un <code>&mut [T]</code><sup id="fnref2"><a href="#fn2" rel="footnote">2</a></sup>, ma, anche qui,
i prestiti sono verificati in fase di esecuzione.</p>
<p>Nei programmi concorrenti, abbiamo una situazione simile con <code>Arc<Mutex<T>></code>,
che fornisce mutabilità e possesso condivisi.</p>
<p>Quando si legge del codice che li usa, si proceda passo per passo,
e si guardi alle garanzie e ai costi forniti.</p>
<p>Quando si sceglie un tipo composito, dobbiamo fare il contrario; decidere
quali garanzie vogliamo, e a quale punto della composizione ci servono.
Per esempio, se c'è una scelta fra <code>Vec<RefCell<T>></code> e <code>RefCell<Vec<T>></code>,
dovremmo decidere i pro e i contro come fatto prima, e sceglierne uno.</p>
<p>e una lunghezza, e possono far riferimento a una porzione di un vettore
o di un array. <code>&mut [T]</code> può avere i suoi elementi mutati, però
la sua lunghezza con può essere toccata.</p>
<div class="footnotes">
<hr>
<ol>
<li id="fn1">
<p><code>Arc<UnsafeCell<T>></code> effettivamente non compilerà, siccome <a href="#fnref1" rev="footnote">↩</a></p>
</li>
<li id="fn2">
<p><code>&[T]</code> e <code>&mut [T]</code> sono delle <em>slice</em>; consistono di un puntatore <a href="#fnref2" rev="footnote">↩</a></p>
</li>
</ol>
</div>
<script type="text/javascript">
window.playgroundUrl = "https://play.rust-lang.org";
</script>
<script src='rustbook.js'></script>
<script src='playpen.js'></script>
</div></div>
</body>
</html>