-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch10-03-lifetime-syntax.html
640 lines (589 loc) · 94.5 KB
/
ch10-03-lifetime-syntax.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
<!DOCTYPE HTML>
<html lang="uk" class="sidebar-visible no-js light">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Перевірка Коректності Посилань із Часами Існування - Мова програмування Rust</title>
<!-- Custom HTML head -->
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="title-page.html">Мова Програмування Rust</a></li><li class="chapter-item expanded affix "><a href="foreword.html">Передмова</a></li><li class="chapter-item expanded affix "><a href="ch00-00-introduction.html">Вступ</a></li><li class="chapter-item expanded "><a href="ch01-00-getting-started.html"><strong aria-hidden="true">1.</strong> Початок</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch01-01-installation.html"><strong aria-hidden="true">1.1.</strong> Встановлення</a></li><li class="chapter-item expanded "><a href="ch01-02-hello-world.html"><strong aria-hidden="true">1.2.</strong> Hello, World!</a></li><li class="chapter-item expanded "><a href="ch01-03-hello-cargo.html"><strong aria-hidden="true">1.3.</strong> Привіт, Cargo!</a></li></ol></li><li class="chapter-item expanded "><a href="ch02-00-guessing-game-tutorial.html"><strong aria-hidden="true">2.</strong> Програмування Гри Відгадайки</a></li><li class="chapter-item expanded "><a href="ch03-00-common-programming-concepts.html"><strong aria-hidden="true">3.</strong> Загальні Концепції Програмування</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch03-01-variables-and-mutability.html"><strong aria-hidden="true">3.1.</strong> Змінні і Мутабельність</a></li><li class="chapter-item expanded "><a href="ch03-02-data-types.html"><strong aria-hidden="true">3.2.</strong> Типи Даних</a></li><li class="chapter-item expanded "><a href="ch03-03-how-functions-work.html"><strong aria-hidden="true">3.3.</strong> Функції</a></li><li class="chapter-item expanded "><a href="ch03-04-comments.html"><strong aria-hidden="true">3.4.</strong> Коментарі</a></li><li class="chapter-item expanded "><a href="ch03-05-control-flow.html"><strong aria-hidden="true">3.5.</strong> Потік Виконання</a></li></ol></li><li class="chapter-item expanded "><a href="ch04-00-understanding-ownership.html"><strong aria-hidden="true">4.</strong> Розуміння Володіння</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch04-01-what-is-ownership.html"><strong aria-hidden="true">4.1.</strong> Що Таке Володіння?</a></li><li class="chapter-item expanded "><a href="ch04-02-references-and-borrowing.html"><strong aria-hidden="true">4.2.</strong> Посилання та Позичання</a></li><li class="chapter-item expanded "><a href="ch04-03-slices.html"><strong aria-hidden="true">4.3.</strong> Слайси</a></li></ol></li><li class="chapter-item expanded "><a href="ch05-00-structs.html"><strong aria-hidden="true">5.</strong> Використання Структур для Групування Пов'язаних Даних</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch05-01-defining-structs.html"><strong aria-hidden="true">5.1.</strong> Визначення та Створення Екземпляра Структури</a></li><li class="chapter-item expanded "><a href="ch05-02-example-structs.html"><strong aria-hidden="true">5.2.</strong> Приклад Програми з Використанням Структур</a></li><li class="chapter-item expanded "><a href="ch05-03-method-syntax.html"><strong aria-hidden="true">5.3.</strong> Синтаксис Методів</a></li></ol></li><li class="chapter-item expanded "><a href="ch06-00-enums.html"><strong aria-hidden="true">6.</strong> Енуми та Зіставлення зі Шаблоном</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch06-01-defining-an-enum.html"><strong aria-hidden="true">6.1.</strong> Визначення Енума</a></li><li class="chapter-item expanded "><a href="ch06-02-match.html"><strong aria-hidden="true">6.2.</strong> Конструкція Потоку Виконання match</a></li><li class="chapter-item expanded "><a href="ch06-03-if-let.html"><strong aria-hidden="true">6.3.</strong> Лаконічний Потік Виконання з if let</a></li></ol></li><li class="chapter-item expanded "><a href="ch07-00-managing-growing-projects-with-packages-crates-and-modules.html"><strong aria-hidden="true">7.</strong> Керування Щораз Більшими Проєктами із Пакетами, Крейтами та Модулями</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch07-01-packages-and-crates.html"><strong aria-hidden="true">7.1.</strong> Пакети та Крейти</a></li><li class="chapter-item expanded "><a href="ch07-02-defining-modules-to-control-scope-and-privacy.html"><strong aria-hidden="true">7.2.</strong> Визначення Модулів для Контролю Області Видимості та Приватності</a></li><li class="chapter-item expanded "><a href="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html"><strong aria-hidden="true">7.3.</strong> Шлях для Доступу до Елементів у Дереві Модулів</a></li><li class="chapter-item expanded "><a href="ch07-04-bringing-paths-into-scope-with-the-use-keyword.html"><strong aria-hidden="true">7.4.</strong> Введення Шляхів до Області Видимості з Ключовим Словом use</a></li><li class="chapter-item expanded "><a href="ch07-05-separating-modules-into-different-files.html"><strong aria-hidden="true">7.5.</strong> Розподіл Модулів на Різні Файли</a></li></ol></li><li class="chapter-item expanded "><a href="ch08-00-common-collections.html"><strong aria-hidden="true">8.</strong> Звичайні Колекції</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch08-01-vectors.html"><strong aria-hidden="true">8.1.</strong> Зберігання Списків Значень з Векторами</a></li><li class="chapter-item expanded "><a href="ch08-02-strings.html"><strong aria-hidden="true">8.2.</strong> Зберігання Тексту у Кодуванні UTF-8 в Стрічках</a></li><li class="chapter-item expanded "><a href="ch08-03-hash-maps.html"><strong aria-hidden="true">8.3.</strong> Зберігання Ключів з Асоційованими Значеннями у Хеш-Мапах</a></li></ol></li><li class="chapter-item expanded "><a href="ch09-00-error-handling.html"><strong aria-hidden="true">9.</strong> Обробка Помилок</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong aria-hidden="true">9.1.</strong> Невідновлювані Помилки з panic!</a></li><li class="chapter-item expanded "><a href="ch09-02-recoverable-errors-with-result.html"><strong aria-hidden="true">9.2.</strong> Відновлювані Помилки з Result</a></li><li class="chapter-item expanded "><a href="ch09-03-to-panic-or-not-to-panic.html"><strong aria-hidden="true">9.3.</strong> panic! чи не panic!</a></li></ol></li><li class="chapter-item expanded "><a href="ch10-00-generics.html"><strong aria-hidden="true">10.</strong> Узагальнені Типи, Трейти та Часи Існування</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch10-01-syntax.html"><strong aria-hidden="true">10.1.</strong> Узагальнені Типи Даних</a></li><li class="chapter-item expanded "><a href="ch10-02-traits.html"><strong aria-hidden="true">10.2.</strong> Трейти: Визначення Спільної Поведінки</a></li><li class="chapter-item expanded "><a href="ch10-03-lifetime-syntax.html" class="active"><strong aria-hidden="true">10.3.</strong> Перевірка Коректності Посилань із Часами Існування</a></li></ol></li><li class="chapter-item expanded "><a href="ch11-00-testing.html"><strong aria-hidden="true">11.</strong> Написання Автоматизованих Тестів</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch11-01-writing-tests.html"><strong aria-hidden="true">11.1.</strong> Як Писати Тести</a></li><li class="chapter-item expanded "><a href="ch11-02-running-tests.html"><strong aria-hidden="true">11.2.</strong> Керування Запуском Тестів</a></li><li class="chapter-item expanded "><a href="ch11-03-test-organization.html"><strong aria-hidden="true">11.3.</strong> Організація Тестів</a></li></ol></li><li class="chapter-item expanded "><a href="ch12-00-an-io-project.html"><strong aria-hidden="true">12.</strong> Проєкт з Вводом/Виводом: Створення Програми з Інтерфейсом Командного Рядка</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch12-01-accepting-command-line-arguments.html"><strong aria-hidden="true">12.1.</strong> Приймання Аргументів Командного Рядка</a></li><li class="chapter-item expanded "><a href="ch12-02-reading-a-file.html"><strong aria-hidden="true">12.2.</strong> Читання Файлу</a></li><li class="chapter-item expanded "><a href="ch12-03-improving-error-handling-and-modularity.html"><strong aria-hidden="true">12.3.</strong> Рефакторинг для Покращення Модульності та Обробки Помилок</a></li><li class="chapter-item expanded "><a href="ch12-04-testing-the-librarys-functionality.html"><strong aria-hidden="true">12.4.</strong> Розробка Функціонала Бібліотеки із Test-Driven Development</a></li><li class="chapter-item expanded "><a href="ch12-05-working-with-environment-variables.html"><strong aria-hidden="true">12.5.</strong> Робота зі Змінними Середовища</a></li><li class="chapter-item expanded "><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong aria-hidden="true">12.6.</strong> Написання Повідомлень про Помилки у Помилковий Вивід замість Стандартного Виводу</a></li></ol></li><li class="chapter-item expanded "><a href="ch13-00-functional-features.html"><strong aria-hidden="true">13.</strong> Функціональні Можливості Мови: Ітератори та Замикання</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch13-01-closures.html"><strong aria-hidden="true">13.1.</strong> Замикання: Анонімні Функції, що Захоплюють Своє Середовище</a></li><li class="chapter-item expanded "><a href="ch13-02-iterators.html"><strong aria-hidden="true">13.2.</strong> Обробка Послідовностей Елементів з Ітераторами</a></li><li class="chapter-item expanded "><a href="ch13-03-improving-our-io-project.html"><strong aria-hidden="true">13.3.</strong> Покращення Нашого Проєкту з Вводом/Виводом</a></li><li class="chapter-item expanded "><a href="ch13-04-performance.html"><strong aria-hidden="true">13.4.</strong> Порівняння Швидкодії: Цикли Проти Ітераторів</a></li></ol></li><li class="chapter-item expanded "><a href="ch14-00-more-about-cargo.html"><strong aria-hidden="true">14.</strong> Більше про Cargo та Crates.io</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch14-01-release-profiles.html"><strong aria-hidden="true">14.1.</strong> Налаштування Збірок з Release Профілями</a></li><li class="chapter-item expanded "><a href="ch14-02-publishing-to-crates-io.html"><strong aria-hidden="true">14.2.</strong> Публікація Крейта на Crates.io</a></li><li class="chapter-item expanded "><a href="ch14-03-cargo-workspaces.html"><strong aria-hidden="true">14.3.</strong> Робочі Області Cargo</a></li><li class="chapter-item expanded "><a href="ch14-04-installing-binaries.html"><strong aria-hidden="true">14.4.</strong> Встановлення Двійкових Файлів з cargo install</a></li><li class="chapter-item expanded "><a href="ch14-05-extending-cargo.html"><strong aria-hidden="true">14.5.</strong> Розширення Cargo із Користувацькими Командами</a></li></ol></li><li class="chapter-item expanded "><a href="ch15-00-smart-pointers.html"><strong aria-hidden="true">15.</strong> Розумні Вказівники</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch15-01-box.html"><strong aria-hidden="true">15.1.</strong> Використання Box<T> для Вказування на Дані в Купі</a></li><li class="chapter-item expanded "><a href="ch15-02-deref.html"><strong aria-hidden="true">15.2.</strong> Ставлення до Розумних Вказівників як до Звичайних Посилань з Трейтом Deref</a></li><li class="chapter-item expanded "><a href="ch15-03-drop.html"><strong aria-hidden="true">15.3.</strong> Виконання Коду при Очищенні з Трейтом Drop</a></li><li class="chapter-item expanded "><a href="ch15-04-rc.html"><strong aria-hidden="true">15.4.</strong> Rc<T> - Розумний Вказівник з Лічильником Посилань</a></li><li class="chapter-item expanded "><a href="ch15-05-interior-mutability.html"><strong aria-hidden="true">15.5.</strong> RefCell<T> та Шаблон Внутрішньої Мутабельності</a></li><li class="chapter-item expanded "><a href="ch15-06-reference-cycles.html"><strong aria-hidden="true">15.6.</strong> Цикли Посилань Можуть Спричинити Витік Пам'яті</a></li></ol></li><li class="chapter-item expanded "><a href="ch16-00-concurrency.html"><strong aria-hidden="true">16.</strong> Безстрашна Конкурентність</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch16-01-threads.html"><strong aria-hidden="true">16.1.</strong> Використання Потоків для Одночасного Виконання Коду</a></li><li class="chapter-item expanded "><a href="ch16-02-message-passing.html"><strong aria-hidden="true">16.2.</strong> Застосування Обміну Повідомлень для Передавання Даних між Потоками</a></li><li class="chapter-item expanded "><a href="ch16-03-shared-state.html"><strong aria-hidden="true">16.3.</strong> Конкурентність зі Спільним Станом</a></li><li class="chapter-item expanded "><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong aria-hidden="true">16.4.</strong> Розширювана Конкурентність із Трейтами Sync та Send</a></li></ol></li><li class="chapter-item expanded "><a href="ch17-00-oop.html"><strong aria-hidden="true">17.</strong> Особливості Об'єктоорієнтованого Програмування в Rust</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch17-01-what-is-oo.html"><strong aria-hidden="true">17.1.</strong> Характеристики Об'єктоорієнтованих Мов</a></li><li class="chapter-item expanded "><a href="ch17-02-trait-objects.html"><strong aria-hidden="true">17.2.</strong> Використання Трейт-Об'єктів, які Допускають Значення Різних Типів</a></li><li class="chapter-item expanded "><a href="ch17-03-oo-design-patterns.html"><strong aria-hidden="true">17.3.</strong> Реалізація Об'єктоорієнтованого Шаблону Проєктування</a></li></ol></li><li class="chapter-item expanded "><a href="ch18-00-patterns.html"><strong aria-hidden="true">18.</strong> Шаблони та Зіставлення Шаблонів</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch18-01-all-the-places-for-patterns.html"><strong aria-hidden="true">18.1.</strong> Усі Місця Можливого Використання Шаблонів</a></li><li class="chapter-item expanded "><a href="ch18-02-refutability.html"><strong aria-hidden="true">18.2.</strong> Спростовуваність: Чи Може Шаблон Бути Невідповідним</a></li><li class="chapter-item expanded "><a href="ch18-03-pattern-syntax.html"><strong aria-hidden="true">18.3.</strong> Синтаксис Шаблонів</a></li></ol></li><li class="chapter-item expanded "><a href="ch19-00-advanced-features.html"><strong aria-hidden="true">19.</strong> Просунуті Можливості</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch19-01-unsafe-rust.html"><strong aria-hidden="true">19.1.</strong> Небезпечний Rust</a></li><li class="chapter-item expanded "><a href="ch19-03-advanced-traits.html"><strong aria-hidden="true">19.2.</strong> Поглиблено про Трейти</a></li><li class="chapter-item expanded "><a href="ch19-04-advanced-types.html"><strong aria-hidden="true">19.3.</strong> Поглиблено про Типи</a></li><li class="chapter-item expanded "><a href="ch19-05-advanced-functions-and-closures.html"><strong aria-hidden="true">19.4.</strong> Поглиблено про Функції та Замикання</a></li><li class="chapter-item expanded "><a href="ch19-06-macros.html"><strong aria-hidden="true">19.5.</strong> Макроси</a></li></ol></li><li class="chapter-item expanded "><a href="ch20-00-final-project-a-web-server.html"><strong aria-hidden="true">20.</strong> Останній Проєкт: Збірка Багатопотокового Вебсервера</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch20-01-single-threaded.html"><strong aria-hidden="true">20.1.</strong> Збірка Однопотокового Вебсервера</a></li><li class="chapter-item expanded "><a href="ch20-02-multithreaded.html"><strong aria-hidden="true">20.2.</strong> Перетворюємо Наш Однопотоковий Сервер на Багатопотоковий</a></li><li class="chapter-item expanded "><a href="ch20-03-graceful-shutdown-and-cleanup.html"><strong aria-hidden="true">20.3.</strong> Плавне Вимкнення та Очищення</a></li></ol></li><li class="chapter-item expanded "><a href="appendix-00.html"><strong aria-hidden="true">21.</strong> Додатки</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="appendix-01-keywords.html"><strong aria-hidden="true">21.1.</strong> A - Ключові Слова</a></li><li class="chapter-item expanded "><a href="appendix-02-operators.html"><strong aria-hidden="true">21.2.</strong> B - Оператори та Символи</a></li><li class="chapter-item expanded "><a href="appendix-03-derivable-traits.html"><strong aria-hidden="true">21.3.</strong> C - Похідні Трейти</a></li><li class="chapter-item expanded "><a href="appendix-04-useful-development-tools.html"><strong aria-hidden="true">21.4.</strong> D - Корисні Інструменти Розробки</a></li><li class="chapter-item expanded "><a href="appendix-05-editions.html"><strong aria-hidden="true">21.5.</strong> E - Видання</a></li><li class="chapter-item expanded "><a href="appendix-06-translation.html"><strong aria-hidden="true">21.6.</strong> F - Переклади Книги</a></li><li class="chapter-item expanded "><a href="appendix-07-nightly-rust.html"><strong aria-hidden="true">21.7.</strong> G - як Розробляється Rust і "Нічний Rust"</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Мова програмування Rust</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h2 id="Перевірка-Коректності-Посилань-із-Часами-Існування"><a class="header" href="#Перевірка-Коректності-Посилань-із-Часами-Існування">Перевірка Коректності Посилань із Часами Існування</a></h2>
<p>Часи існування є ще одним узагальненим типом даних, який ми вже використовували. Замість того щоб гарантувати, що тип має бажану поведінку, часи існування гарантують що посилання є валідним доти, доки воно може бути нам потрібним.</p>
<p>В частині <a href="">“Посилання і позичання”</a><!-- ignore --> четвертого розділу ми не згадали про те, що кожне посилання в Rust має свій <em>час існування</em>, який обмежує час протягом якого посилання є дійсним. В більшості випадків, часи існування є неявними (implicit) та виведеними (inferred), так само як і типи. Ми зобовʼязані додавати анотації лише у випадках коли можливий більше ніж один тип. Відповідно, ми мусимо додавати анотації до часів існування лише якщо останні можуть бути використані у кілька різних способів. Rust зобовʼязує нас анотувати звʼязки використовуючи узагальнені параметри часу існування, щоб впевнитися що посилання використані протягом часу виконання програми будуть коректними.</p>
<p>Додавання анотацій для часів існування не є поширеним в інших мовах програмування, тож може бути здаватися дещо складним для сприйняття. Попри те що в цьому розділі ми не розглядатимемо всі деталі часів існування, ми обговоримо їх найбільш загальні способи використання, щоб в подальшому у вас не виникало проблем зі сприйняттям цієї концепції.</p>
<h3 id="Запобігання-Висячим-Посиланням-із-Часами-Існування"><a class="header" href="#Запобігання-Висячим-Посиланням-із-Часами-Існування">Запобігання Висячим Посиланням із Часами Існування</a></h3>
<p>Головною метою використання часів існування є запобігання <em>висячим посиланням</em>, які зберігають в памʼяті дані, котрі більше не будуть використані програмою. Розглянемо приклад з блоку коду 10-16, який має внутрішню і зовнішню область видимості.</p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("r: {}", r);
}
</code></pre>
<p><span class="caption">Блок коду 10-16: Спроба використати посилання, значення якого лежить за межами області видимості</span></p>
<blockquote>
<p>Примітка: Приклади у Блоках коду 10-16, 10-17 та 10-23 проголошують змінні без надання їм початкового значення, тож, назва змінної існує в зовнішньої області видимості. На перший погляд, може видатися, що це суперечить тому, що Rust не має нульових значень. Однак, якщо ми спробуємо використати змінну перед наданням їй значення, ми отримаємо помилку часу компіляції, що показує, що Rust дійсно не допускає значення null.</p>
</blockquote>
<p>Зовнішня область видимості проголошує змінну з назвою <code>r</code> без початкового значення, а внутрішня область видимості проголошує змінну з назвою <code>x</code> з початковим значенням 5. Усередині внутрішньої області видимості ми намагаємося встановити значення r у посилання до <code>x</code>. Тоді внутрішня область видимості закінчується, і ми намагаємося вивести значення <code>r</code>. Цей код не компілюється, бо значення, на яке посилається <code>r</code>, вийшло з області видимості до того, як ми спробували ним скористатися. Ось повідомлення про помилку:</p>
<pre><code class="language-console">$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0597]: `x` does not live long enough
--> src/main.rs:6:13
|
6 | r = &x;
| ^^ borrowed value does not live long enough
7 | }
| - `x` dropped here while still borrowed
8 |
9 | println!("r: {}", r);
| - borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `chapter10` due to previous error
</code></pre>
<p>Змінна <code>x</code> не "існує достатньо довго". Причина в тому, що <code>x</code> вийде з області видимості коли внутрішня область видимості скінчиться у рядку 7. Але змінна <code>r</code> все ще валідна у зовнішній області видимості; оскільки її область видимості більша, ми кажемо, що вона "існує довше". Якби Rust дозволив цьому коду працювати, <code>r</code> посилався би на пам'ять, що була звільнена, коли <code>x</code> вийшов з області видимості, і все, що ми намагатимемося робити з <code>r</code>, не працюватиме належним чином. То як Rust визначає, що код є некоректним? Вона використовує borrow checker.</p>
<h3 id="the-borrow-checker"><a class="header" href="#the-borrow-checker">The Borrow Checker</a></h3>
<p>Компілятор Rust має <em>borrow checker</em>, який порівнює області видимості і визначає, чи всі позичання валідні. Блок коду 10-17 показує такий самий код, як у Блоці коду 10-16, але з анотаціями, які показують часи існування змінних.</p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
</code></pre>
<p><span class="caption">Блок коду 10-17: анотації часів існування <code>r</code> та <code>x</code>, що називаються відповідно <code>'a</code> та <code>'b</code></span></p>
<p>Тут ми анотували час існування <code>r</code> як <code>'a</code> і час існування <code>x</code> як <code>'b</code>. Як бачите, час існування внутрішнього блоку <code>'b</code> є набагато меншим, ніж зовнішнього <code>'a</code>. Під час компіляції Rust порівнює розмір двох часів існування і бачить, що <code>r</code> має час існування <code>'a</code>, але він посилається на пам'ять з часом існування <code>'b</code>. Програма буде відхилена через те, що <code>'b</code> коротший за <code>'a</code>: те, на що посилаються, існує менше, ніж посилання.</p>
<p>Блок коду 10-18 виправляє код, щоб не було висячого посилання, і компілюється без жодних помилок.</p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let x = 5; // ----------+-- 'b
// |
let r = &x; // --+-- 'a |
// | |
println!("r: {}", r); // | |
// --+ |
} // ----------+
</code></pre></pre>
<p><span class="caption">Блок коду 10-18: посилання є валідним, бо дані мають довший час існування, ніж посилання</span></p>
<p>Тут <code>x</code> має час існування <code>'b</code>, що у цьому випадку більше, ніж <code>'a</code>. Це означає, що <code>r</code> може посилатись на <code>x</code>, тому що Rust знає, що посилання в <code>r</code> завжди буде дійсним, поки <code>x</code> є дійсним.</p>
<p>Тепер, коли ви знаєте, де знаходяться часи існування посилань і як Rust аналізує часи існування, щоб гарантувати, що посилання завжди будуть валідними, розгляньмо узагальнені часи існування параметрів та значень, що повертаються, в контексті функцій.</p>
<h3 id="Узагальнені-Часи-Існування-у-Функціях"><a class="header" href="#Узагальнені-Часи-Існування-у-Функціях">Узагальнені Часи Існування у Функціях</a></h3>
<p>Ми напишемо функцію, яка повертає довший з двох стрічкових слайсів. Ця функція прийматиме два стрічкові слайси і повертатиме один слайс. Після реалізації функції <code>longest</code>, код у Блоці коду 10-19 має вивести <code>The longest string is abcd</code>.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><code class="language-rust ignore">fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("The longest string is {}", result);
}
</code></pre>
<p><span class="caption">Блок коду 10-19: функція <code>main</code>, що викликає функцію <code>longest</code> щоб знайти довший з двох стрічкових слайсів</span></p>
<p>Зверніть увагу, що нам потрібно, щоб функція приймала рядки фрагментів, які є посиланнями, а не стрічки, тому що ми не хочемо, щоб функція <code>longest</code> брала володіння над своїми параметрами. Зверніться до підрозділу <a href="">"Стрічкові слайси як параметри"</a><!-- ignore --> Розділу 4 для детальнішого обговорення, чому ми хочемо використати саме такі параметри в Блоці коду 10-19.</p>
<p>Якщо ми спробуємо реалізувати функцію <code>longest</code> як показано у Блоці коду 10-20, вона не скомпілюється.</p>
<p><span class="filename">Файл: src/lib.rs</span></p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
</span><span class="boring"> let string1 = String::from("abcd");
</span><span class="boring"> let string2 = "xyz";
</span><span class="boring">
</span><span class="boring"> let result = longest(string1.as_str(), string2);
</span><span class="boring"> println!("The longest string is {}", result);
</span><span class="boring">}
</span><span class="boring">
</span>fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
</code></pre>
<p><span class="caption">Блок коду 10-20: реалізація функції <code>longest</code>, що повертає довший з двох стрічкових слайсів, але ще не компілюється</span></p>
<p>Натомість ми отримуємо наступну помилку, яка говорить про часи існування:</p>
<pre><code class="language-console">$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0106]: missing lifetime specifier
--> src/main.rs:9:33
|
9 | fn longest(x: &str, y: &str) -> &str {
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
|
9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
| ++++ ++ ++ ++
For more information about this error, try `rustc --explain E0106`.
error: could not compile `chapter10` due to previous error
</code></pre>
<p>Текст підказки показує, що тип, який повертається, потребує для себе вказаного узагальненого часу існування, оскільки Rust не може сказати, буде повернуте посилання <code>x</code> чи <code>y</code>. Насправді ми також цього не знаємо, оскільки блок <code>if</code> у тілі цієї функції повертає посилання на <code>x</code>, а блок <code>else</code> повертає посилання на <code>y</code>!</p>
<p>Коли ми визначаємо цю функцію, ми не знаємо конкретних значень, які будуть передані в цю функцію, тому ми не знаємо, спрацює випадок <code>if</code> чи <code>else</code>. Ми також не знаємо конкретного часу існування посилань, які будуть передані, тож ми не можемо подивитися на область видимості, як ми робили у Блоках коду 10-17 та 10-18, щоб визначити, чи посилання, яке ми повертаємо, буде завжди валідним. Borrow checker також не може визначити цього, оскільки він не знає як час існування <code>x</code> або <code>y</code> стосується часу існування значення, що повертається. Щоб виправити цю помилку, ми додамо узагальнені параметри часу існування, які визначають зв'язок між посиланнями, щоб borrow checker міг його проаналізувати.</p>
<h3 id="Синтаксис-Анотації-Часу-Існування"><a class="header" href="#Синтаксис-Анотації-Часу-Існування">Синтаксис Анотації Часу Існування</a></h3>
<p>Анотації часу існування не змінюють як довго існує посилання. Натомість вони описують взаємозв'язок часів існування багатьох посилань між собою, не впливаючи на ці часи існування. Так само як функції можуть приймати будь-який тип, коли сигнатура визначає параметр узагальненого типу, функції можуть приймати посилання з будь-яким часом існування, якщо заданий узагальнений параметр часу існування.</p>
<p>Анотації часу існування мають дещо незвичний синтаксис: імена параметрів часу існування мають починатися на апостроф (<code>'</code>) і зазвичай в нижньому регістрі та дуже короткі, як узагальнені типи. Більшість людей використовують ім'я <code>'a</code> для першої анотації часу існування. Ми розміщуємо анотації часу існування параметрів після <code>&</code> посилання, використовуючи пробіл для відокремлення анотації від типу посилання.</p>
<p>Ось кілька прикладів: посилання на <code>i32</code> без параметру часу існування, посилання на на <code>i32</code>, що має параметр часу існування <code>'a</code>, і мутабельне посилання на <code>i32</code>, що також має час існування <code>'a</code>.</p>
<pre><code class="language-rust ignore">&i32 // посилання
&'a i32 // посилання з явним часом існування
&'a mut i32 // мутабельне посилання з явним часом існування
</code></pre>
<p>Сам по собі одна анотація часу існування не має великого значення. оскільки анотації мають повідомляти Rust, як узагальнені параметри часу існування багатьох посилань співвідносяться один з одним. Дослідімо, як анотації часу існування співвідносяться одна з одною в контексті функції <code>longest</code>.</p>
<h3 id="Анотації-Часу-Існування-у-Сигнатурах-Функцій"><a class="header" href="#Анотації-Часу-Існування-у-Сигнатурах-Функцій">Анотації Часу Існування у Сигнатурах Функцій</a></h3>
<p>Щоб використовувати анотації часу існування в сигнатурах функцій, ми маємо проголосити узагальнений параметр <em>часу існування</em> в кутових дужках між назвою функції і списком параметрів, так, як це робиться з узагальненими параметрами <em>типу</em>.</p>
<p>Ми хочемо, щоб сигнатура виражала наступне обмеження: повернуте посилання буде валідним стільки, скільки обидва параметри будуть валідними. Це відношення між часом існування параметрів та значення, що повертається. Ми назвемо час існування <code>'a</code>, а тоді додамо його до кожного посилання, як показано в Блоці коду 10-21.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span><span class="boring"> let string1 = String::from("abcd");
</span><span class="boring"> let string2 = "xyz";
</span><span class="boring">
</span><span class="boring"> let result = longest(string1.as_str(), string2);
</span><span class="boring"> println!("The longest string is {}", result);
</span><span class="boring">}
</span><span class="boring">
</span>fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
</code></pre></pre>
<p><span class="caption">Блок коду 10-21: Визначення функції <code>longest</code> із зазначенням, що всі посилання у сигнатурі повинні мати однаковий час існування <code>'a</code></span></p>
<p>Цей код має компілюватися і створювати бажаний результат, коли ми використовуємо його у функції <code>main</code> у Блоці коду 10-19.</p>
<p>Сигнатура функції тепер повідомляє Rust, що для якогось часу існування <code>'a</code> функція приймає два параметри, обидва з яких - стрічкові слайси, які існують принаймні так довго, як час існування <code>'a</code>. Сигнатура функції також каже Rust, що стрічковий слайс, повернутий з функції, існуватиме щонайменше так довго, як час існування <code>'a</code>. На практиці це означає, що час існування посилання, повернутого функцією <code>longest</code>, дорівнює коротшому з часів існування значень, на які посилаються аргументи функції. Ці відносини - це те, що ми хочемо, щоб Rust використовувала під час аналізу цього коду.</p>
<p>Пам'ятайте, що коли ми зазначаємо час існування параметрів на сигнатурі цієї функції, ми не змінюємо час існування жодного значення, які передаються або повертаються. Радше ми уточнюємо, що borrow checker повинен відкидати будь-які значення, які не відповідають цим обмеженням. Зверніть увагу, що функція <code>longest</code> не повинна точно знати, як довго <code>x</code> і <code>y</code> будуть існувати, лише те, що деяка область видимості може бути замінена на <code>'a</code> що задовольняє цій сигнатурі.</p>
<p>При анотації часів існування у функції анотації зазначаються у сигнатурі функції, а не в її тілі. Анотації часу існування стають частиною контракту функції, так само, як типи у сигнатурі. Те, що сигнатури функцій містять контракт на час існування, означає, що аналіз, який робить компілятор Rust, буде простішим. Якщо є проблема з тим, як функція анотована або як її викликають, помилки компілятора можуть точніше вказувати на частину нашого коду та обмеження. Якщо натомість компілятор Rust робив більше припущень про те, якими ми хотіли б бачити відносини між часами існування, компілятор міг би вказувати лише на використання нашого коду за багато кроків від причини проблеми.</p>
<p>Коли ми передаємо конкретні посилання до <code>longest</code>, конкретний час існування, що підставляється в <code>'a</code>, є частиною області видимості <code>x</code>, що перетинається з областю видимості <code>y</code>. Іншими словами, узагальнений час існування <code>'a</code> отримає конкретний час існування, що є рівним меншому з часів існування <code>x</code> та <code>y</code>. Оскільки ми анотували посилання, що повертається, тим самим параметром часу існування <code>'a</code>, посилання, що повертається, також буде валідним під час тривалості меншого з часів інсування <code>x</code> та <code>y</code>.</p>
<p>Подивімося, як анотації часу існування обмежують функцію <code>longest</code>, передаючи посилання, що мають різне конкретні часи існування. Блок коду 10-22 надає прямолінійний приклад.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let string1 = String::from("long string is long");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("The longest string is {}", result);
}
}
<span class="boring">
</span><span class="boring">fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
</span><span class="boring"> if x.len() > y.len() {
</span><span class="boring"> x
</span><span class="boring"> } else {
</span><span class="boring"> y
</span><span class="boring"> }
</span><span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок коду 10-22: використання функції "longest" з посиланнями на значення "String", які мають різний конкретний час існування</span></p>
<p>У цьому прикладі <code>string1</code> буде валідним до кінця зовнішньої області видимості, <code>string2</code> до кінця внутрішньої області видимості, а <code>result</code> посилається на щось, що є валідним до кінця внутрішньої області видимості. Запустіть цей код, і ви побачите, що borrow checker його приймає; код скомпілюється і виведе <code>The longest string is long string is long</code>.</p>
<p>Далі розгляньмо приклад, який показує, що час існування посилання в <code>result</code> має бути меншим з тривалостей існування двох аргументів. Ми перемістимо оголошення змінної <code>result</code> за межі внутрішньої області видимості, але залишимо присвоєння значення змінній <code>result</code> усередині області видимості зі <code>string2</code>. Потім ми перемістимо <code>println!</code>, який використовує <code>result</code>, за межі внутрішньої області видимості, її після закінчення. Код в Блоці коду 10-23 не скомпілюється.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let string1 = String::from("long string is long");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
println!("The longest string is {}", result);
}
<span class="boring">
</span><span class="boring">fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
</span><span class="boring"> if x.len() > y.len() {
</span><span class="boring"> x
</span><span class="boring"> } else {
</span><span class="boring"> y
</span><span class="boring"> }
</span><span class="boring">}
</span></code></pre>
<p><span class="caption">Блок коду 10-23: спроба використати <code>result</code> після виходу <code>string2</code> з області видимості</span></p>
<p>Якщо ми спробуємо скомпілювати цей код, то отримаємо таку помилку:</p>
<pre><code class="language-console">$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0597]: `string2` does not live long enough
--> src/main.rs:6:44
|
6 | result = longest(string1.as_str(), string2.as_str());
| ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
7 | }
| - `string2` dropped here while still borrowed
8 | println!("The longest string is {}", result);
| ------ borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `chapter10` due to previous error
</code></pre>
<p>Помилка показує, що для того, що <code>result</code> був валідним для інструкції <code>println!</code>, <code>string2</code> має бути валідним до кінця зовнішньої області видимості. Rust знає це, бо ми анотували час існування параметрів функції та значення, що повертається, за допомогою того самого параметра часу існування <code>'a</code>.</p>
<p>Як люди, ми можемо подивитися на цей код і побачити, що <code>string1</code> довша за <code>string2</code> і тому <code>result</code> міститиме посилання на <code>string1</code>. Оскільки <code>string1</code> ще не вийшла з області видимості, посилання на <code>string1</code> все ще буде валідним для інструкції <code>println!</code>. Однак, компілятор не може побачити, що посилання в цьому випадку валідне. Ми повідомили Rust, що час існування посилання, що повертається функцією <code>longest</code>, такий самий, як менший з часів існування переданих їй посилань. Тому borrow checker забороняє код у Блоці коду 10-23 як такий, що потенційно містить неправильне посилання.</p>
<p>Спробуйте провести більше експериментів, які змінюють значення і часи існування посилань, переданих у функцію <code>longest</code>, а також використання посилання, що повертається. Робіть припущення про те, чи пройдуть ваші експерименти borrow checker до компіляції; потім перевірте, щоб побачити, чи маєте ви рацію!</p>
<h3 id="Мислення-в-Термінах-Часів-Існування"><a class="header" href="#Мислення-в-Термінах-Часів-Існування">Мислення в Термінах Часів Існування</a></h3>
<p>Спосіб, яким треба позначати параметри часу існування, залежить від того, що саме робить ваша функція. Наприклад, якби ми змінили реалізацію функції <code>longest</code>, щоб та завжди повертала перший параметр замість найдовшої стрічки, то нам не потрібно було б вказувати час існування для параметра <code>y</code>. Цей код буде скомпілюється:</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span><span class="boring"> let string1 = String::from("abcd");
</span><span class="boring"> let string2 = "efghijklmnopqrstuvwxyz";
</span><span class="boring">
</span><span class="boring"> let result = longest(string1.as_str(), string2);
</span><span class="boring"> println!("The longest string is {}", result);
</span><span class="boring">}
</span><span class="boring">
</span>fn longest<'a>(x: &'a str, y: &str) -> &'a str {
x
}
</code></pre></pre>
<p>Ми зазначили параметр часу існування <code>'a</code> для параметра <code>x</code> та типу, що повертається, але не для параметра <code>y</code>, оскільки час існування <code>у</code> у не має стосунку до часу існування <code>x</code> або значення, що повертається.</p>
<p>При поверненні посилання з функції, параметр часу існування для типу, що повертається, має збігатися з параметром часу існування для одного з параметрів. Якщо повернуте посилання <em>не</em> посилається на один з параметрів, воно повинне посилатись на значення, створене всередині цієї функції. Однак це буде висяче посилання, тому що значення вийде з області видимості в кінці функції. Розглянемо спробу реалізації функції <code>longest</code>, яка не компілюється:</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
</span><span class="boring"> let string1 = String::from("abcd");
</span><span class="boring"> let string2 = "xyz";
</span><span class="boring">
</span><span class="boring"> let result = longest(string1.as_str(), string2);
</span><span class="boring"> println!("The longest string is {}", result);
</span><span class="boring">}
</span><span class="boring">
</span>fn longest<'a>(x: &str, y: &str) -> &'a str {
let result = String::from("really long string");
result.as_str()
}
</code></pre>
<p>Тут, хоча ми й зазначили параметр часу існування <code>'a</code> для типу, що повертається, ця реалізація не буде скомпільованою, оскільки час існування значення, що повертається, взагалі не пов'язаний з часом існування параметрів. Ось яке повідомлення про помилку ми отримаємо:</p>
<pre><code class="language-console">$ cargo run
Compiling chapter10 v0.1.0 (file:///projects/chapter10)
error[E0515]: cannot return reference to local variable `result`
--> src/main.rs:11:5
|
11 | result.as_str()
| ^^^^^^^^^^^^^^^ returns a reference to data owned by the current function
For more information about this error, try `rustc --explain E0515`.
error: could not compile `chapter10` due to previous error
</code></pre>
<p>Проблема в тому, що <code>result</code> виходить з області видимості й очищується в кінці функції <code>longest</code>. Ми також намагаємося повернути з функції посилання на <code>result</code>. Неможливо вказати параметри часу існування, які змінять висяче посилання, і Rust не дозволяє нам створити висяче посилання. У цьому випадку найкращим виправленням було б повернути тип, що володіє даними, замість посилання, щоб функція, яка викликала, була б відповідальною за очищення значення.</p>
<p>Зрештою, синтаксис часу існування стосується зв'язування часів існування різних параметрів і значень, що повертаються з функцій. Коли вони пов'язуються, Rust має достатньо інформації, щоб дозволити безпечні операції з пам'яттю і забороняти операції, які створювали б висячі вказівники або іншим чином порушували безпеку пам’яті.</p>
<h3 id="Анотації-Часів-Існування-у-Визначеннях-Структур"><a class="header" href="#Анотації-Часів-Існування-у-Визначеннях-Структур">Анотації Часів Існування у Визначеннях Структур</a></h3>
<p>Досі всі визначені нами структури містили типи, що володіють даними. Ми можемо визначити структури, що міститимуть посилання, але в цьому разі ми маємо додати анотацію часу існування до кожного посилання у визначенні структури. Блок коду 10-24 демонструє структуру, що зветься <code>ImportantExcerpt</code>, що містить стрічковий слайс.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">struct ImportantExcerpt<'a> {
part: &'a str,
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
let i = ImportantExcerpt {
part: first_sentence,
};
}
</code></pre></pre>
<p><span class="caption">Блок коду 10-24: структура, що містить посилання, яке потребує анотації часу існування</span></p>
<p>Ця структура має єдине поле <code>part</code>, що містить стрічковий слайс, що є посиланням. Як і для узагальнених типів даних, ми проголошуємо назву узагальненого параметру часу існування в кутових дужках після назви структури, щоб ми могли використати цей параметр часу існування у визначенні структури. Ця анотація означає, що екземпляр <code>ImportantExcerpt</code> не може існувати довше, ніж посилання, яке він містить у своєму полі <code>part</code>.</p>
<p>Функція <code>main</code> тут створює екземпляр структури <code>ImportantExcerpt</code>, який містить посилання на перше речення <code>String</code>, якою володіє змінна <code>novel</code>. Дані в <code>novel</code> існують до створення екземпляра <code>ImportantExcerpt</code>. Крім того, <code>novel</code> не виходить з області видимості, доки <code>ImportantExcerpt</code> не вийде з області видимості, тож посилання в екземплярі <code>ImportantExcerpt</code> є валідним.</p>
<h3 id="Елізія-Часу-Існування"><a class="header" href="#Елізія-Часу-Існування">Елізія Часу Існування</a></h3>
<p>Ви дізналися, що кожне посилання має час існування і ви маєте зазначити параметри часу існування для функцій та структур, які використовують посилання. Однак у Розділі 4 у нас була функція в Блоці коду 4-9, показана знову у Блоці коду 10-25, яка скомпілювалася без анотацій часу існування.</p>
<p><span class="filename">Файл: src/lib.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> let my_string = String::from("hello world");
</span><span class="boring">
</span><span class="boring"> // first_word works on slices of `String`s
</span><span class="boring"> let word = first_word(&my_string[..]);
</span><span class="boring">
</span><span class="boring"> let my_string_literal = "hello world";
</span><span class="boring">
</span><span class="boring"> // first_word works on slices of string literals
</span><span class="boring"> let word = first_word(&my_string_literal[..]);
</span><span class="boring">
</span><span class="boring"> // Because string literals *are* string slices already,
</span><span class="boring"> // this works too, without the slice syntax!
</span><span class="boring"> let word = first_word(my_string_literal);
</span><span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок коду 10-25: функція, визначена в Блоці коду 4-9, яка компілюється без анотацій часу існування, хоча параметр і тип, що повертається є посиланнями</span></p>
<p>Причина, чому ця функція компілюється без анотацій часу існування, є історичною: у ранніх версіях (до 1.0) Rust цей код не скомпілювався б тому, що кожне посилання потребувало явного часу існування. На той момент сигнатура функції була б записана так:</p>
<pre><code class="language-rust ignore">fn first_word<'a>(s: &'a str) -> &'a str {
</code></pre>
<p>Після написання великої кількості коду на Rust, команда Rust виявила, що програмісти Rust вводять ті самі анотації часу існування знову і знову в конкретних випадках. Ці ситуації були передбачуваними та відповідали декільком визначеним шаблонів. Розробники запрограмували ці шаблони у код компілятора, щоб borrow checker міг вивести часи існування в цих ситуаціях і не потребував явних анотацій.</p>
<p>Цей шматок історії Rust має значення, оскільки цілком можливо, що буде виявлено ще більше визначених шаблонів і будуть додані до компілятора. Можливо, у майбутньому буде потрібно ще менше анотацій часу існування.</p>
<p>Шаблони, запрограмовані в аналіз посилань Rust, називаються <em>правилами елізії часів існування</em>. Це не правила для програмістів; вони є набором певних випадків, які розглядає компілятор, і якщо ваш код відповідає цим випадкам, вам не потрібно явно вказувати часи існування.</p>
<p>Правила елізії не забезпечують повного виведення. Якщо Rust детерміновано застосовує правила, але залишається невизначеність щодо того, які часи існування мають посилання, компілятор не зможе здогадатися, якими мають бути часи існування решти посилань. Замість відгадування компілятор дасть вам помилку, котру ви можете її усунути, додавши анотації часів існування.</p>
<p>Часи існування на параметрах функції чи методу називаються <em>вхідні часи існування</em>, а часи існування на значеннях, що повертаються - <em>вихідні часи існування</em>.</p>
<p>Компілятор використовує три правила, щоб знайти час існування для посилань, коли немає явних анотацій. Перше правило застосовується до вхідних часів існування, а друге і третє правила до вихідного часу існування. Якщо компілятор досягає закінчуння трьох правил все ще є посилання, для яких він не може визначити часи існування, компілятор зупиниться з помилкою. Ці правила застосовуються до проголошень <code>fn</code>, а також до блоків <code>impl</code>.</p>
<p>Перше правило полягає в тому, що компілятор встановлює параметр часу існування для кожного параметра, що є посиланням. Іншими словами, функція з одним параметром отримує один параметр часу існування: <code>fn foo<'a>(x: &'a i32)</code>; функція з двома параметрами отримує два окремі параметри часу існування:<code>fn foo<'a, 'b>(x: &'a i32, y: &'b i32)</code>; і так далі.</p>
<p>Друге правило полягає в тому, що якщо існує рівно один вхідний параметр часу існування, цей час існування призначається на всі вихідні параметри часів існування: <code>fn foo<'a>(x: &'a i32) -> &'a i32</code>.</p>
<p>Третє правило полягає в тому, що якщо є багато вхідних параметрів часу існування, але один з них є <code>&self</code> or <code>&mut self</code>, бо це метод, час існування <code>self</code> призначається усім вихідним параметрам часу існування. Це третє правило набагато полегшує читання і писання методів, бо потрібно менше символів.</p>
<p>Зробімо вигляд, що ми компілятор. Ми застосуємо ці правила, щоб визначити часи існування посилань у сигнатурі функції <code>first_word</code> у Блоці коду 10-25. Сигнатура починається без жодних часів існування, пов'язаних із посиланнями:</p>
<pre><code class="language-rust ignore">fn first_word(s: &str) -> &str {
</code></pre>
<p>Потім компілятор застосовує перше правило, яке визначає, що кожен параметр отримує свій власний час існування. Ми назвемо його <code>'a</code>, як зазвичай, тому тепер сигнатура є такою:</p>
<pre><code class="language-rust ignore">fn first_word<'a>(s: &'a str) -> &str {
</code></pre>
<p>Друге правило застосовується, бо тут є рівно один вхідний час існування. Друге правило каже, що час існування єдиного вхідного параметра призначається вихідному часу існування, тож сигнатура тепер така:</p>
<pre><code class="language-rust ignore">fn first_word<'a>(s: &'a str) -> &'a str {
</code></pre>
<p>Тепер всі посилання в сигнатурі цієї функції мають часи існування, і компілятор може продовжити свій аналіз, не змушуючи програміста анотувати часи існування в сигнатурі цієї функції.</p>
<p>Розгляньмо інший приклад, цього разу з функцією <code>longest</code>, яка не мала параметрів часу існування, коли ми почали працювати з нею у Блоці коду 10-20:</p>
<pre><code class="language-rust ignore">fn longest(x: &str, y: &str) -> &str {
</code></pre>
<p>Застосуємо перше правило: кожен параметр отримує свій час існування. Цього разу ми маємо два параметри замість одного, тому ми маємо два часи існування:</p>
<pre><code class="language-rust ignore">fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &str {
</code></pre>
<p>Як бачите, друге правило не застосовується, тому що є більш ніж один вхідний час існування. Третє правило також не застосовується, тому що <code>longest</code> є функцією, а не методом, тож жоден з параметрів не є <code>self</code>. Виконавши всі три правила, ми все ще не з'ясували час існування типу, що повертається. Саме тому ми отримали помилку при спробі скомпілювати код у Блоці коду 10-20: компілятор пропрацював правила елізії часів існування, але все ж не зміг з'ясувати всі часи існування посилань у сигнатурі.</p>
<p>Оскільки третє правило застосовується тільки в сигнатурі методів, далі ми подивимося на часи існування в цьому контексті, щоб зрозуміти, чому третє правило означає, що нам не дуже часто доводиться анотувати часи існування у сигнатурах методів.</p>
<h3 id="Анотації-Часів-Існування-у-Визначеннях-Методів"><a class="header" href="#Анотації-Часів-Існування-у-Визначеннях-Методів">Анотації Часів Існування у Визначеннях Методів</a></h3>
<p>Коли ми реалізовуємо методи для структур з часами існування, то використовуємо той самий синтаксис, що і параметри узагальненого типу, показані у Блоці коду 10-11. Де нам проголошувати і використовувати параметри часу існування, залежить від того, чи стосуються вони полів структури, чи параметрів методу і значення, що повертається.</p>
<p>Назви часу існування полів структур завжди треба проголошувати після ключового слова <code>impl</code>, а потім використовувати після назви структури, тому що ці часи існування є частиною типу структури.</p>
<p>У сигнатурах методів всередині блоку <code>impl</code> посилання мають бути або прив'язані до часу існування посилань у полях структури, або ж мають бути незалежними. Крім того, правила елізії часів існування часто роблять анотації часів існування непотрібними у сигнатурах методів. Погляньмо на деякі приклади, використовуючи структуру з назвою <code>ImportantExcerpt</code>, яку ми визначили у Блоці коду 10-24.</p>
<p>Спершу, ми використовуємо метод з назвою <code>level</code>, єдиним параметром якого є посилання на <code>self</code>, а значення, що повертається є <code>i32</code>, що не є посиланням:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">struct ImportantExcerpt<'a> {
</span><span class="boring"> part: &'a str,
</span><span class="boring">}
</span><span class="boring">
</span>impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
}
<span class="boring">
</span><span class="boring">impl<'a> ImportantExcerpt<'a> {
</span><span class="boring"> fn announce_and_return_part(&self, announcement: &str) -> &str {
</span><span class="boring"> println!("Attention please: {}", announcement);
</span><span class="boring"> self.part
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> let novel = String::from("Call me Ishmael. Some years ago...");
</span><span class="boring"> let first_sentence = novel.split('.').next().expect("Could not find a '.'");
</span><span class="boring"> let i = ImportantExcerpt {
</span><span class="boring"> part: first_sentence,
</span><span class="boring"> };
</span><span class="boring">}
</span></code></pre></pre>
<p>Декларація параметра часу існування після <code>impl</code> і його використання після назви типу є необхідними, але ми не маємо анотувати час існування посилання на <code>self</code> через перше правило елізії.</p>
<p>Ось приклад, де застосовується третє правило елізії часу існування:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">struct ImportantExcerpt<'a> {
</span><span class="boring"> part: &'a str,
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl<'a> ImportantExcerpt<'a> {
</span><span class="boring"> fn level(&self) -> i32 {
</span><span class="boring"> 3
</span><span class="boring"> }
</span><span class="boring">}
</span><span class="boring">
</span>impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> let novel = String::from("Call me Ishmael. Some years ago...");
</span><span class="boring"> let first_sentence = novel.split('.').next().expect("Could not find a '.'");
</span><span class="boring"> let i = ImportantExcerpt {
</span><span class="boring"> part: first_sentence,
</span><span class="boring"> };
</span><span class="boring">}
</span></code></pre></pre>
<p>Тут є два вхідних часи існування, тож Rust застосовує перше правило елізії часів існування і дає обом <code>&self</code> та <code>announcement</code> власні часи існування. Тоді, оскільки один з параметрів є <code>&self</code>, тип, що повертається. отримує час існування <code>&self</code>, і всі часи існування було призначено.</p>
<h3 id="Статичний-Час-Існування"><a class="header" href="#Статичний-Час-Існування">Статичний Час Існування</a></h3>
<p>Ми маємо обговорити один особливий час існування - <code>'static</code>, що позначає, що посилання <em>може</em> існувати весь час роботи програми. Всі стрічкові літерали мають час існування <code>'static</code>, що ми можемо анотувати таким чином:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let s: &'static str = "I have a static lifetime.";
<span class="boring">}
</span></code></pre></pre>
<p>Текст цієї стрічки зберігається безпосередньо в двійковому файлі програми, який є завжди доступним. Таким чином, час життя усіх стрічкових літералів є <code>'static</code>.</p>
<p>Ви можете побачити пропозиції використовувати час існування <code>'static</code> у повідомленнях про помилки. Але перш ніж вказати часом існування посилання <code>'static</code>, подумайте, чи дійсно ваше посилання існує впродовж усієї роботи вашої програми чи ні, і чи хочете, щоб воно таким було. У більшості випадків повідомлення про помилку, що пропонує час існування <code>'static</code> є результатом спроби створити висяче посилання чи невідповідність наявних часів існування. У таких випадках рішенням є виправити ці проблеми, а не визначити час існування <code>'static</code>.</p>
<h2 id="Параметри-Узагальненого-Типу-Обмеження-Трейтів-і-Часи-Існування-Разом"><a class="header" href="#Параметри-Узагальненого-Типу-Обмеження-Трейтів-і-Часи-Існування-Разом">Параметри Узагальненого Типу, Обмеження Трейтів і Часи Існування Разом</a></h2>
<p>Подивімося коротко на синтаксис визначення параметрів узагальненого типу, обмежень трейтів і часів існування разом в одній функції!</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span><span class="boring"> let string1 = String::from("abcd");
</span><span class="boring"> let string2 = "xyz";
</span><span class="boring">
</span><span class="boring"> let result = longest_with_an_announcement(
</span><span class="boring"> string1.as_str(),
</span><span class="boring"> string2,
</span><span class="boring"> "Today is someone's birthday!",
</span><span class="boring"> );
</span><span class="boring"> println!("The longest string is {}", result);
</span><span class="boring">}
</span><span class="boring">
</span>use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: Display,
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
</code></pre></pre>
<p>Це функція <code>longest</code> зі Блоку коду 10-21, яка повертає довший із двох стрічкових слайсів. Але тепер вона має додатковий параметр з назвою <code>ann</code> узагальненого типу <code>T</code>, який може бути заповнений будь-яким типом, який реалізує трейт <code>Display</code>, як зазначено в клаузі <code>where</code>. Цей додатковий параметр буде виведено за допомогою <code>{}</code>, то й робить необхідним обмеження трейту <code>Display</code>. Оскільки часи існування є узагальненням, проголошення параметра часу існування <code>'a</code> і параметру узагальненого типу <code>T</code> розміщуються в одному списку в кутових дужках після назви функції.</p>
<h2 id="Підсумок"><a class="header" href="#Підсумок">Підсумок</a></h2>
<p>Ми багато відкрили в цьому розділі! Тепер, коли ви знаєте про параметри узагальненого типу, трейти і трейтові обмеження, і узагальнені параметри часу існування, ви готові написати код без повторень, що працюватиме у багатьох різних ситуаціях. Параметри узагальнених типів дозволяють вам застосовувати один код для різних типів. Трейти та трейтові обмеження гарантують, що навіть якщо типи є узагальненими, вони матимуть поведінку, потрібну коду. Ви вивчили, як використовувати анотації часу існування, щоб убезпечити такий гнучкий код від висячих посилань. І відбувається весь цей аналіз під час компіляції, що не впливає на продуктивність під час виконання!</p>
<p>Вірите ви чи ні, є ще багато чого, що можна дізнатися про обговорені в цьому розділі теми: Розділ 17 обговорює трейтові об'єкти, які є іншим способом використання трейтів. Також є складніші сценарії, що використовують анотації часів існування, що знадобляться вам лише у дуже просунутих сценаріях; для них ви маєте прочитати <a href="../reference/index.html">Rust Reference</a>. Та зараз ви навчитеся писати тести на Rust, щоб переконатися, що ваш код працює так, як треба.
ch04-02-references-and-borrowing.html#references-and-borrowing ch04-03-slices.html#string-slices-as-parameters</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch10-02-traits.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch11-00-testing.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ch10-02-traits.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="ch11-00-testing.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script type="text/javascript">
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>