forked from carlomilanesi/linguaggio-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
closures.html
892 lines (720 loc) · 47.7 KB
/
closures.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
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
<!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>Chiusure ["closure"]</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 class='active' 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 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">Chiusure ["closure"]</h1>
<p>Talvolta è utile racchiudere una funzione e le <em>variabili libere</em> per ottenere
maggiore chiarezza e riutilizzo. Le variabili libere che possono essere usate
vengono dall'ambito circostante, e vengono 'rinchiuse' quando vengono
usate nella funzione. Da ciò deriva il nome ‘chiusura’, e Rust ne fornisce
un'implementazione davvero ottima, come vedremo.</p>
<h1 id='sintassi' class='section-header'><a href='#sintassi'>Sintassi</a></h1>
<p>Le chiusure si presentano così:</p>
<span class='rusttest'>fn main() {
let piu_uno = |x: i32| x + 1;
assert_eq!(6, piu_uno(5));
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>piu_uno</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>1</span>;
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>piu_uno</span>(<span class='number'>5</span>));</pre>
<p>Abbiamo creato un legame, <code>piu_uno</code>, e l'abbiamo assegnato a una chiusura.
Gli argomenti della chiusura vanno fra due caratteri 'pipe' (<code>|</code>);
mentre il corpo della chiusura è un'espressione, in questo caso, <code>x + 1</code>.
Si noti che <code>{ }</code> è un'espressione, e quindi si possono scrivere chiusure
che contengono più istruzioni, in questo modo:</p>
<span class='rusttest'>fn main() {
let piu_due = |x| {
let mut risultato: i32 = x;
risultato += 1;
risultato += 1;
risultato
};
assert_eq!(9, piu_due(7));
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>piu_due</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> {
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>risultato</span>: <span class='ident'>i32</span> <span class='op'>=</span> <span class='ident'>x</span>;
<span class='ident'>risultato</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='ident'>risultato</span> <span class='op'>+=</span> <span class='number'>1</span>;
<span class='ident'>risultato</span>
};
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>9</span>, <span class='ident'>piu_due</span>(<span class='number'>7</span>));</pre>
<p>Si notino alcune cose riguardo le chiusure che sono un po' diverse dalle
normali funzioni con nome definite tramite <code>fn</code>. La prima cosa è che
non abbiamo dovuto annotare i tipi degli argomenti che la chiusura prende
né il valore che restituisce. È consentito:</p>
<span class='rusttest'>fn main() {
let piu_uno = |x: i32| -> i32 { x + 1 };
assert_eq!(6, piu_uno(5));
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>piu_uno</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='op'>-></span> <span class='ident'>i32</span> { <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>1</span> };
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>piu_uno</span>(<span class='number'>5</span>));</pre>
<p>ma non è obbligatorio. Perché? Di base, è stato scelto per praticità. Mentre
specificare il tipo completo per le funzioni con nome è di aiuto con cose
come la documentazione e le interfacce dei tipi, le complete firme dei tipi
delle chiusure sono documentate di rado dato che sono anonime, e non
provocano il tipo di errori a distanza che possono essere provocati
dall'inferire i tipi delle funzioni con nome.</p>
<p>La seconda cosa è che la sintassi è simile, ma un po' diversa. Qui sono
stati aggiunti spazi per facilitare il confronto:</p>
<span class='rusttest'>fn main() {
fn piu_uno_v1 (x: i32) -> i32 { x + 1 }
let piu_uno_v2 = |x: i32| -> i32 { x + 1 };
let piu_uno_v3 = |x: i32| x + 1 ;
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>piu_uno_v1</span> (<span class='ident'>x</span>: <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> { <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>1</span> }
<span class='kw'>let</span> <span class='ident'>piu_uno_v2</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='op'>-></span> <span class='ident'>i32</span> { <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>1</span> };
<span class='kw'>let</span> <span class='ident'>piu_uno_v3</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>1</span> ;</pre>
<p>Piccole differenze, ma sono simili.</p>
<h1 id='le-chiusure-e-il-loro-ambiente' class='section-header'><a href='#le-chiusure-e-il-loro-ambiente'>Le chiusure e il loro ambiente</a></h1>
<p>L'ambiente per una chiusura può comprendere i legami del suo ambito
circostante oltre agli argomenti e ai legami locali. Si presenta così:</p>
<span class='rusttest'>fn main() {
let numero = 5;
let piu_numero = |x: i32| x + numero;
assert_eq!(10, piu_numero(5));
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='kw'>let</span> <span class='ident'>piu_numero</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>numero</span>;
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>10</span>, <span class='ident'>piu_numero</span>(<span class='number'>5</span>));</pre>
<p>Questa chiusura, <code>piu_numero</code>, fa riferimento a un legame <code>let</code>
nel suo ambito: <code>numero</code>. Più specificamente, prende in prestito il legame.
Se facciamo qualcosa che entrasse in conflitto con quel legame, otterremmo
un errore. Come questo:</p>
<span class='rusttest'>fn main() {
let mut numero = 5;
let piu_numero = |x: i32| x + numero;
let y = &mut numero;
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='kw'>let</span> <span class='ident'>piu_numero</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>numero</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'>numero</span>;</pre>
<p>Che va in errore con:</p>
<pre><code class="language-text">error: cannot borrow `numero` as mutable because it is also borrowed as immutable
let y = &mut numero;
^~~~~~
note: previous borrow of `numero` occurs here due to use in closure; the immutable
borrow prevents subsequent moves or mutable borrows of `numero` until the borrow
ends
let piu_numero = |x| x + numero;
^~~~~~~~~~~~~~~~
note: previous borrow ends here
fn main() {
let mut numero = 5;
let piu_numero = |x| x + numero;
let y = &mut numero;
}
^
</code></pre>
<p>Un messaggio d'errore prolisso ma utile! Come dice, non si può prendere <code>num</code>
a prestito mutabile, perché la chiusura lo sta già tenendo a prestito.
Ma se lasciamo uscire di ambito la chiusura, lo possiamo fare:</p>
<span class='rusttest'>fn main() {
let mut numero = 5;
{
let piu_numero = |x: i32| x + numero;
} // piu_numero esce di ambito, e quindi il prestito di 'numero' finisce
let y = &mut numero;
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
{
<span class='kw'>let</span> <span class='ident'>piu_numero</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>numero</span>;
} <span class='comment'>// piu_numero esce di ambito, e quindi il prestito di 'numero' finisce</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'>numero</span>;</pre>
<p>Però, se la chiusura lo richiede, Rust invece prenderà il possesso del legame
e lo sposterà dall'ambiente. Quindi questo non funziona:</p>
<span class='rusttest'>fn main() {
let numeri = vec![1, 2, 3];
let prende_numeri = || numeri;
println!("{:?}", numeri);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>numeri</span> <span class='op'>=</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='kw'>let</span> <span class='ident'>prende_numeri</span> <span class='op'>=</span> <span class='op'>||</span> <span class='ident'>numeri</span>;
<span class='macro'>println</span><span class='macro'>!</span>(<span class='string'>"{:?}"</span>, <span class='ident'>numeri</span>);</pre>
<p>Otteniamo questo errore:</p>
<pre><code class="language-text">note: `numeri` moved into closure environment here because it has type
`[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
let prende_numeri = || numeri;
^~~~~~~~~
</code></pre>
<p><code>Vec<T></code> ha il possesso del suo contenuto, e quindi, quando
facciamo riferimento ad esso nella nostra chiusura, dobbiamo prendere
possesso di <code>numeri</code>. È lo stesso come se avessimo passato <code>numeri</code>
a una funzione che ne prendesse il possesso.</p>
<h2 id='le-chiusure-move' class='section-header'><a href='#le-chiusure-move'>Le chiusure <code>move</code></a></h2>
<p>Possiamo costringere la nostra chiusura a prendere possesso del suo ambiente
con la parola-chiave <code>move</code>:</p>
<span class='rusttest'>fn main() {
let numero = 5;
let possiede_numero = move |x: i32| x + numero;
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='kw'>let</span> <span class='ident'>possiede_numero</span> <span class='op'>=</span> <span class='kw'>move</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>numero</span>;</pre>
<p>Adesso, anche se la parola-chiave è <code>move</code>, le variabili seguono
la normale semantica di spostamento. In questo caso, <code>5</code> implementa <code>Copy</code>,
e così <code>possiede_numero</code> prende possesso di una copia di <code>numero</code>.
E allora che differenza c'è?</p>
<span class='rusttest'>fn main() {
let mut numero = 5;
{
let mut aggiungi_numero = |x: i32| numero += x;
aggiungi_numero(5);
}
assert_eq!(10, numero);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
{
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>aggiungi_numero</span> <span class='op'>=</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>numero</span> <span class='op'>+=</span> <span class='ident'>x</span>;
<span class='ident'>aggiungi_numero</span>(<span class='number'>5</span>);
}
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>10</span>, <span class='ident'>numero</span>);</pre>
<p>Quindi in questo caso, la nostra chiusura ha preso un riferimento mutabile
a <code>numero</code>, e poi, quando abbiamo chiamato <code>aggiungi_numero</code>, ha mutato
il valore soggiacente, come ci aspettavamo. Abbiamo anche dovuto dichiarare
<code>aggiungi_numero</code> come <code>mut</code>, perché stiamo mutando il suo ambiente.</p>
<p>Se lo trasformiamo in una chiusura <code>move</code>, sarà diverso:</p>
<span class='rusttest'>fn main() {
let mut numero = 5;
{
let mut aggiungi_numero = move |x: i32| numero += x;
aggiungi_numero(5);
}
assert_eq!(5, numero);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>numero</span> <span class='op'>=</span> <span class='number'>5</span>;
{
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>aggiungi_numero</span> <span class='op'>=</span> <span class='kw'>move</span> <span class='op'>|</span><span class='ident'>x</span>: <span class='ident'>i32</span><span class='op'>|</span> <span class='ident'>numero</span> <span class='op'>+=</span> <span class='ident'>x</span>;
<span class='ident'>aggiungi_numero</span>(<span class='number'>5</span>);
}
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>5</span>, <span class='ident'>numero</span>);</pre>
<p>Otteneniamo solamente <code>5</code>. Invece di prendere un prestito mutabile sul
nostro <code>numero</code>, abbiamo preso possesso di una sua copia.</p>
<p>Un altro modo di pensare alle chiusure <code>move</code>: danno a una chiusura
il suo stesso frame di stack. Senza <code>move</code>, una chiusura può essere
vincolata al frame di stack che l'ha creata, mentre una chiusura <code>move</code>
è autocontenuta. Ciò comporta, per esempio, che in generale una funzione
non può restituire una chiusura non-<code>move</code>.</p>
<p>Ma prima di parlare di come prendere e restituire chiusure, dovremmo
parlare ancora un po' del modo in cui le chiusure sono implementate.
Essendo un linguaggio di sistemi, Rust dà moltissimo controllo su ciò che fa
il codice, e le chiusure non sono da meno.</p>
<h1 id='implementazione-delle-chiusure' class='section-header'><a href='#implementazione-delle-chiusure'>Implementazione delle chiusure</a></h1>
<p>L'implementazione delle chiusure di Rust è un po' diversa dagli altri
linguaggi. Effettivamente sono un addolcimento sintattico dei tratti.
Prima di leggere questa sezione, ci si assicuri di aver letto la sezione
sui <a href="traits.html">tratti</a>, e anche quella sugli <a href="trait-objects.html">oggetti-tratto</a>.</p>
<p>Capito tutto? Bene.</p>
<p>La chiave per capire come funzionano sotto il cofano le chiusure è qualcosa
di un po' strano: Usare <code>()</code> per chiamare una funzione, come in <code>foo()</code>,
è un operatore sovraccaricabile. Da questo, tutto il resto scatta
al suo posto. In Rust, si usa il sistema dei tratti per sovraccaricare
gli operatori. Chiamare funzioni non è diverso. Ci sono tre tratti distinti
da sovraccaricare:</p>
<span class='rusttest'>fn main() {
mod foo {
pub trait Fn<Args> : FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
pub trait FnMut<Args> : FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
}
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>pub</span> <span class='kw'>trait</span> <span class='ident'>Fn</span><span class='op'><</span><span class='ident'>Args</span><span class='op'>></span> : <span class='ident'>FnMut</span><span class='op'><</span><span class='ident'>Args</span><span class='op'>></span> {
<span class='kw'>extern</span> <span class='string'>"rust-call"</span> <span class='kw'>fn</span> <span class='ident'>call</span>(<span class='kw-2'>&</span><span class='self'>self</span>, <span class='ident'>args</span>: <span class='ident'>Args</span>) <span class='op'>-></span> <span class='self'>Self</span>::<span class='ident'>Output</span>;
}
<span class='kw'>pub</span> <span class='kw'>trait</span> <span class='ident'>FnMut</span><span class='op'><</span><span class='ident'>Args</span><span class='op'>></span> : <span class='ident'>FnOnce</span><span class='op'><</span><span class='ident'>Args</span><span class='op'>></span> {
<span class='kw'>extern</span> <span class='string'>"rust-call"</span> <span class='kw'>fn</span> <span class='ident'>call_mut</span>(<span class='kw-2'>&</span><span class='kw-2'>mut</span> <span class='self'>self</span>, <span class='ident'>args</span>: <span class='ident'>Args</span>) <span class='op'>-></span> <span class='self'>Self</span>::<span class='ident'>Output</span>;
}
<span class='kw'>pub</span> <span class='kw'>trait</span> <span class='ident'>FnOnce</span><span class='op'><</span><span class='ident'>Args</span><span class='op'>></span> {
<span class='kw'>type</span> <span class='ident'>Output</span>;
<span class='kw'>extern</span> <span class='string'>"rust-call"</span> <span class='kw'>fn</span> <span class='ident'>call_once</span>(<span class='self'>self</span>, <span class='ident'>args</span>: <span class='ident'>Args</span>) <span class='op'>-></span> <span class='self'>Self</span>::<span class='ident'>Output</span>;
}</pre>
<p>Si noteranno alcune differenze fra questi tratti, ma una grossa è <code>self</code>:
<code>Fn</code> prende <code>&self</code>, <code>FnMut</code> prende <code>&mut self</code>, e <code>FnOnce</code> prende <code>self</code>.
Ciò considera tutte e tre i generi di <code>self</code> permessi dalla solita sintassi
di chiamata di metodo. Ma li abbiamo separati in tre tratti, invece
di averne uno solo. Questo ci consente di controllare con precisione
quali generi di chiusure possiamo prendere.</p>
<p>La sintassi <code>|| {}</code> per le chiusure è un addolcimento per questi tre tratti.
Rust genererà una struct che rappresenta l'ambiente, implementerà il tratto
appropriato per essa, e poi lo userà.</p>
<h1 id='prendere-chiusure-come-argomenti' class='section-header'><a href='#prendere-chiusure-come-argomenti'>Prendere chiusure come argomenti</a></h1>
<p>Adesso che sappiamo che le chiusure sono tratti, sappiamo già come accettare
e restituire le chiusure: proprio come ogni altro tratto!</p>
<p>Ciò comporta anche che possiamo scegliere tra il dispatch statico e
quello dinamico. Prima, scriviamo una funzione che prende qualcosa
di chiamabile, lo chiamiamo, e restituiamo il risultato:</p>
<span class='rusttest'>fn main() {
fn chiama_con_uno<F>(una_chiusura: F) -> i32
where F : Fn(i32) -> i32 {
una_chiusura(1)
}
let risposta = chiama_con_uno(|x| x + 2);
assert_eq!(3, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_uno</span><span class='op'><</span><span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>: <span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span>
<span class='kw'>where</span> <span class='ident'>F</span> : <span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='ident'>una_chiusura</span>(<span class='number'>1</span>)
}
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>chiama_con_uno</span>(<span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>2</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>3</span>, <span class='ident'>risposta</span>);</pre>
<p>Passiamo la nostra chiusura, <code>|x| x + 2</code>, a <code>chiama_con_uno</code>, che fa quello
che dice il suo nome: chiama la chiusura, dandole <code>1</code> come argomento.</p>
<p>Esaminiamo la firma di <code>chiama_con_uno</code> più in profondità:</p>
<span class='rusttest'>fn main() {
fn chiama_con_uno<F>(una_chiusura: F) -> i32
where F : Fn(i32) -> i32 {
una_chiusura(1) }
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_uno</span><span class='op'><</span><span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>: <span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span></pre>
<p>Prendiamo un argomente, che è di tipo <code>F</code>. Inoltre restituiamo un <code>i32</code>.
Questa parte non è interessante. La prossima parte è:</p>
<span class='rusttest'>fn main() {
fn chiama_con_uno<F>(una_chiusura: F) -> i32
where F : Fn(i32) -> i32 {
una_chiusura(1) }
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>where</span> <span class='ident'>F</span> : <span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {</pre>
<p>Siccome <code>Fn</code> è un tratto, possiamo vincolare ad esso il nostro generico.
In questo caso, la nostra chiusura prende un <code>i32</code> come argomento
e restituisce un <code>i32</code>, e quindi il vincolo generico che usiamo
è <code>Fn(i32) -> i32</code>.</p>
<p>Qui c'è un altro punto chiave: siccome stiamo vincolando un generico
con un tratto, questo diventerà monomorfizzato, e perciò, nella chiusura
faremo un dispatch statico. È piuttosto pulito. In molti linguaggi,
le chiusure sono inerentemente allocate su heap, e comporteranno sempre
un dispatch dinamico. In Rust, possiamo allocare su stack l'ambiente
della nostra chiusura, e il eseguire un dispatch statico della chiamata.
Ciò accade davvero spesso con gli iteratori e i loro adattatori,
che spesso prendono come argomenti delle chiusure.</p>
<p>Naturalmente, se vogliamo un dispatch dinamico, possiamo averlo.
Un oggetto-tratto gestisce questo caso, come al solito:</p>
<span class='rusttest'>fn main() {
fn chiama_con_uno(una_chiusura: &Fn(i32) -> i32) -> i32 {
una_chiusura(1)
}
let risposta = chiama_con_uno(&|x| x + 2);
assert_eq!(3, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_uno</span>(<span class='ident'>una_chiusura</span>: <span class='kw-2'>&</span><span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='ident'>una_chiusura</span>(<span class='number'>1</span>)
}
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>chiama_con_uno</span>(<span class='kw-2'>&</span><span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='number'>2</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>3</span>, <span class='ident'>risposta</span>);</pre>
<p>Adesso prendiamo un oggetto-tratto, un <code>&Fn</code>. E dobbiamo creare
un riferimento alla nostra chiusura, quando la passiamo a <code>chiama_con_uno</code>,
e quindi usiamo <code>&||</code>.</p>
<p>Una nota veloce sulle chiusure che usano tempi di vita espliciti.
Talvolta si potrebbe avere una chiusura che prende un riferimento così:</p>
<span class='rusttest'>fn main() {
fn chiama_con_riferimento<F>(una_chiusura:F) -> i32
where F: Fn(&i32) -> i32 {
let mut value = 0;
una_chiusura(&value)
}
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_riferimento</span><span class='op'><</span><span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>:<span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span>
<span class='kw'>where</span> <span class='ident'>F</span>: <span class='ident'>Fn</span>(<span class='kw-2'>&</span><span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>value</span> <span class='op'>=</span> <span class='number'>0</span>;
<span class='ident'>una_chiusura</span>(<span class='kw-2'>&</span><span class='ident'>value</span>)
}</pre>
<p>Normalmente si può specificare il tempo di vita dell'argomento alla chiusura.
Potremmo annotarlo nella dichiarazione della funzione:</p>
<span class='rusttest'>fn main() {
fn chiama_con_riferimento<'a, F>(una_chiusura:F) -> i32
where F: Fn(&'a i32) -> i32 {
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_riferimento</span><span class='op'><</span><span class='lifetime'>'a</span>, <span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>:<span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span>
<span class='kw'>where</span> <span class='ident'>F</span>: <span class='ident'>Fn</span>(<span class='kw-2'>&</span><span class='lifetime'>'a</span> <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {</pre>
<p>Però ciò presenta un problema nel nostro caso. Quando si specifica
il tempo di vita esplicito in una funzione, questo lega quel tempo di vita
all'*intero* ambito della funzione invece che appena all'ambito
di invocazione della nostra chiusura. Ciò comporta che il verificatore
dei prestiti vedrà un riferimento mutabile nel medesimo tempo di vita
del nostro riferimento immutabile, non potrà compilarlo.</p>
<p>Per poter dire che ci serve solamente che il tempo di vita sia valido per
l'ambito di invocazione della chiusura, possiamo usare i vincoli dei tratti
di rango superiore ("Higher-Ranked Trait Bounds") con la sintassi <code>for<...></code>:</p>
<span class='rusttest'>fn main() {
fn chiama_con_riferimento<F>(una_chiusura:F) -> i32
where F: for<'a> Fn(&'a i32) -> i32 {
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_riferimento</span><span class='op'><</span><span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>:<span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span>
<span class='kw'>where</span> <span class='ident'>F</span>: <span class='kw'>for</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> <span class='ident'>Fn</span>(<span class='kw-2'>&</span><span class='lifetime'>'a</span> <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {</pre>
<p>Ciò consente al compilatore Rust di trovare il tempo di vita minimo
per invocare la nostra chiusura, e soddisfare le regole del verificatore
dei prestiti. Quindi la nostra funzione potrà essere compilata ed eseguita
come ci aspettiamo.</p>
<span class='rusttest'>fn main() {
fn chiama_con_riferimento<F>(una_chiusura:F) -> i32
where F: for<'a> Fn(&'a i32) -> i32 {
let mut value = 0;
una_chiusura(&value)
}
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_riferimento</span><span class='op'><</span><span class='ident'>F</span><span class='op'>></span>(<span class='ident'>una_chiusura</span>:<span class='ident'>F</span>) <span class='op'>-></span> <span class='ident'>i32</span>
<span class='kw'>where</span> <span class='ident'>F</span>: <span class='kw'>for</span><span class='op'><</span><span class='lifetime'>'a</span><span class='op'>></span> <span class='ident'>Fn</span>(<span class='kw-2'>&</span><span class='lifetime'>'a</span> <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='kw'>let</span> <span class='kw-2'>mut</span> <span class='ident'>value</span> <span class='op'>=</span> <span class='number'>0</span>;
<span class='ident'>una_chiusura</span>(<span class='kw-2'>&</span><span class='ident'>value</span>)
}</pre>
<h1 id='puntatori-a-funzione-e-chiusure' class='section-header'><a href='#puntatori-a-funzione-e-chiusure'>Puntatori a funzione e chiusure</a></h1>
<p>Un puntatore a funzione è un po' come una chiusura che non ha nessun ambiente.
Come tale, si può passare un puntatore a funzione a qualunque funzione
che si aspetta come argomento una chiusura, e funzionerà:</p>
<span class='rusttest'>fn main() {
fn chiama_con_uno(una_chiusura: &Fn(i32) -> i32) -> i32 {
una_chiusura(1)
}
fn aggiungi_uno(i: i32) -> i32 {
i + 1
}
let f = aggiungi_uno;
let risposta = chiama_con_uno(&f);
assert_eq!(2, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>chiama_con_uno</span>(<span class='ident'>una_chiusura</span>: <span class='kw-2'>&</span><span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='ident'>una_chiusura</span>(<span class='number'>1</span>)
}
<span class='kw'>fn</span> <span class='ident'>aggiungi_uno</span>(<span class='ident'>i</span>: <span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span> {
<span class='ident'>i</span> <span class='op'>+</span> <span class='number'>1</span>
}
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>aggiungi_uno</span>;
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>chiama_con_uno</span>(<span class='kw-2'>&</span><span class='ident'>f</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>2</span>, <span class='ident'>risposta</span>);</pre>
<p>In questo esempio, non abbiamo strettamente bisogno della variabile
intermedia <code>f</code>; il nome della funzione va altrettanto bene:</p>
<span class='rusttest'>fn main() {
let risposta = chiama_con_uno(&aggiungi_uno);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>chiama_con_uno</span>(<span class='kw-2'>&</span><span class='ident'>aggiungi_uno</span>);</pre>
<h1 id='restituire-chiusure' class='section-header'><a href='#restituire-chiusure'>Restituire chiusure</a></h1>
<p>È molto tipico per il codice in stile funzionale restituire delle chiusure
in varie situazioni. Se si prova a restituire una chiusura, ci si può
imbattere in un errore. Dapprima, può sembrare strano, ma vedremo perché.
Ecco un tentativo plausibile di restituire una chiusura da una funzione:</p>
<span class='rusttest'>fn main() {
fn factory() -> (Fn(i32) -> i32) {
let num = 5;
|x| x + num
}
let f = factory();
let risposta = f(1);
assert_eq!(6, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>factory</span>() <span class='op'>-></span> (<span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span>) {
<span class='kw'>let</span> <span class='ident'>num</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>num</span>
}
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>factory</span>();
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>f</span>(<span class='number'>1</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>risposta</span>);</pre>
<p>Questo ci dà questi lunghi errori correlati:</p>
<pre><code class="language-text">error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
fn factory() -> (Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
fn factory() -> (Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~
error: the trait bound `core::ops::Fn(i32) -> i32 : core::marker::Sized` is not satisfied [E0277]
let f = factory();
^
note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
let f = factory();
^
</code></pre>
<p>Per poter restituire qualcosa da una funzione, Rust deve conoscere
la dimensione del tipo del valore restituito. Ma siccome <code>Fn</code> è un tratto,
potrebbe essere varie cose di varie dimensioni: molti tipi diversi possono
implementare <code>Fn</code>. Un modo facile per dare una dimensione a qualcosa è
prendere un riferimento ad esso, dato che i riferimenti hanno
una dimensione nota. Quindi scriveremmo questo:</p>
<span class='rusttest'>fn main() {
fn factory() -> &(Fn(i32) -> i32) {
let num = 5;
|x| x + num
}
let f = factory();
let risposta = f(1);
assert_eq!(6, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>factory</span>() <span class='op'>-></span> <span class='kw-2'>&</span>(<span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span>) {
<span class='kw'>let</span> <span class='ident'>num</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>num</span>
}
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>factory</span>();
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>f</span>(<span class='number'>1</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>risposta</span>);</pre>
<p>Ma otteniamo un altro errore:</p>
<pre><code class="language-text">error: missing lifetime specifier [E0106]
fn factory() -> &(Fn(i32) -> i32) {
^~~~~~~~~~~~~~~~~
</code></pre>
<p>Giusto. Siccome abbiamo un riferimento, dobbiamo dargli un tempo di vita.
Ma la nostra funzione <code>factory()</code> non prende argomenti, e quindi qui
l'<a href="lifetimes.html#lifetime-elision">elisione</a> non entra in gioco.
Allora che scelte abbiamo? Possiamo provare <code>'static</code>:</p>
<span class='rusttest'>fn main() {
fn factory() -> &'static (Fn(i32) -> i32) {
let num = 5;
|x| x + num
}
let f = factory();
let risposta = f(1);
assert_eq!(6, risposta);
}</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>factory</span>() <span class='op'>-></span> <span class='kw-2'>&</span><span class='lifetime'>'static</span> (<span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span>) {
<span class='kw'>let</span> <span class='ident'>num</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>num</span>
}
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>factory</span>();
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>f</span>(<span class='number'>1</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>risposta</span>);</pre>
<p>Ma otteniamo un altro errore:</p>
<pre><code class="language-text">error: mismatched types:
expected `&'static core::ops::Fn(i32) -> i32`,
found `[closure@<anon>:7:9: 7:20]`
(expected &-ptr,
found closure) [E0308]
|x| x + num
^~~~~~~~~~~
</code></pre>
<p>Questo errore ci fa sapere che non abbiamo una <code>&'static Fn(i32) -> i32</code>,
abbiamo una <code>[closure@<anon>:7:9: 7:20]</code>. Un attimo, cos'è?</p>
<p>Siccome ogni chiusura genera la sua <code>struct</code> ambiente e
la sua implementazione di <code>Fn</code> e compagni, questi tipo sono anonimi.
Esistono solamente per questa chiusura. Quindi Rust li mostra come
<code>closure@<anon></code>, invece di mostrare un nome autogenerato.</p>
<p>L'errore fa notare anche che come tipo del valore restituito ci si
aspetta un riferimento, ma quello che stiamo provando a restituire non lo è.
Inoltre, non possiamo assegnare direttamente un tempo di vita <code>'static</code>
a un oggetto. Quindi sceglieremo un approccio diverso e restituiremo
un oggetto-tratto incapsulando la <code>Fn</code> in un <code>Box</code>. Questo <em>quasi</em> funziona:</p>
<span class='rusttest'>fn factory() -> Box<Fn(i32) -> i32> {
let num = 5;
Box::new(|x| x + num)
}
fn main() {
let f = factory();
let risposta = f(1);
assert_eq!(6, risposta);
}
</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>factory</span>() <span class='op'>-></span> <span class='ident'>Box</span><span class='op'><</span><span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span><span class='op'>></span> {
<span class='kw'>let</span> <span class='ident'>num</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='ident'>Box</span>::<span class='ident'>new</span>(<span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>num</span>)
}
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>factory</span>();
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>f</span>(<span class='number'>1</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>risposta</span>);</pre>
<p>C'è appena un ultimo difetto:</p>
<pre><code class="language-text">error: closure may outlive the current function, but it borrows `num`,
which is owned by the current function [E0373]
Box::new(|x| x + num)
^~~~~~~~~~~
</code></pre>
<p>Beh, come abbiamo discusso prima, le chiusure prendono in prestito
il loro ambiente. E in questo caso, il nostro ambiente è basato su un <code>5</code>
allocato sullo stack, il legame di variabile <code>num</code>. Quindi il prestito
ha il tempo di vita del frame di stack. Perciò se restituissimo
questa chiusura, la chiamata di funzione finirebbe, il frame di stack
andrebbe via, e la nostra chiusura avrebbe catturato un ambiente di memoria
spazzatura! Con un'ultima correzione, lo possiamo far funzionare:</p>
<span class='rusttest'>fn factory() -> Box<Fn(i32) -> i32> {
let num = 5;
Box::new(move |x| x + num)
}
fn main() {
let f = factory();
let risposta = f(1);
assert_eq!(6, risposta);
}
</span><pre class='rust rust-example-rendered'>
<span class='kw'>fn</span> <span class='ident'>factory</span>() <span class='op'>-></span> <span class='ident'>Box</span><span class='op'><</span><span class='ident'>Fn</span>(<span class='ident'>i32</span>) <span class='op'>-></span> <span class='ident'>i32</span><span class='op'>></span> {
<span class='kw'>let</span> <span class='ident'>num</span> <span class='op'>=</span> <span class='number'>5</span>;
<span class='ident'>Box</span>::<span class='ident'>new</span>(<span class='kw'>move</span> <span class='op'>|</span><span class='ident'>x</span><span class='op'>|</span> <span class='ident'>x</span> <span class='op'>+</span> <span class='ident'>num</span>)
}
<span class='kw'>fn</span> <span class='ident'>main</span>() {
<span class='kw'>let</span> <span class='ident'>f</span> <span class='op'>=</span> <span class='ident'>factory</span>();
<span class='kw'>let</span> <span class='ident'>risposta</span> <span class='op'>=</span> <span class='ident'>f</span>(<span class='number'>1</span>);
<span class='macro'>assert_eq</span><span class='macro'>!</span>(<span class='number'>6</span>, <span class='ident'>risposta</span>);
}</pre>
<p>Rendendo la chiusura interna un <code>move Fn</code>, creiamo un nuovo frame di stack
per la nostra chiusura. Incapsulandolo in un <code>Box</code>, gli abbiamo dato
una dimensione nota, consentendogli di fuggire dal nostro frame di stack.</p>
<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>