-
Notifications
You must be signed in to change notification settings - Fork 0
/
ch04-01-what-is-ownership.html
475 lines (411 loc) · 75.3 KB
/
ch04-01-what-is-ownership.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
<!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" class="active"><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"><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><em>Володіння</em> - це набір правил, які регулюють, як програма на Rust керує пам'яттю. Усі програми мають керувати тим, як вони використовують пам'ять комп'ютера під час роботи. Деякі мови мають збирача сміття, який постійно шукає пам'ять, що її вже не використовують, під час роботи програми; в інших мовах програміст має явно виділяти та звільняти пам'ять. Rust використовує третій підхід: пам'ять управляється системою володіння з набором правил, які перевіряє компілятор. Якщо якесь із правил порушується, програма не скомпілюється. Жодна з особливостей володіння не сповільніть вашу програму під час виконання.</p>
<p>Оскільки володіння - нова концепція для багатьох програмістів, потрібен деякий час, щоб звикнути до нього. Добра новина - що досвідченішим ви ставатимете в Rust і правилах системи володіння, тим легшим для вас буде природно писати безпечний і ефективний код. Не здавайтеся!</p>
<p>Коли ви зрозумієте володіння, ви матимете надійну основу для розуміння особливостей, що роблять Rust унікальною мовою. В цьому розділі ви вивчите володіння, працюючи з прикладами, що зосереджуються на добре відомих структурах даних: рядках.</p>
<blockquote>
<h3 id="Стек-і-Купа"><a class="header" href="#Стек-і-Купа">Стек і Купа</a></h3>
<p>У багатьох мовах програмування програміст нечасто має думати про стек і купу. Але в системних мовах, таких, як Rust, розташування значення в стеку чи в купі впливає на поведінку програми й змушує вас ухвалювати певні рішення. Деталі володіння будуть описані стосовно стека та купи пізніше у цьому розділі, а тут коротке пояснення для підготовки.</p>
<p>І стек, і купа - частини пам'яті, до яких ваш код має доступ під час виконання, але вони мають різну структуру. Стек зберігає значення в порядку, в якому їх отримує, і видаляє їх у зворотньому порядку. Це зветься <em>останнім надійшов, першим пішов (last in, first out)</em>. Стек можна уявити, як стос тарілок: коли ви додаєте тарілки, треба ставити їх зверху, а коли треба зняти тарілку, то доводиться брати теж зверху. Додавання чи прибирання тарілок з середини чи знизу стосу матимуть значно гірший наслідок! Додавання даних також зветься <em>заштовхуванням у стек (push</em>), а видалення - відповідно, <em>виштовхуванням (pop</em>). Усі дані. що зберігаються в стеку, мають бути відомого і незмінного розміру. Дані, розмір яких невідомий під час компіляції, або може змінитися, мають зберігатися в купі.</p>
<p>Купа менш організована: коли ви розміщуєте дані в купі, то запитуєте певний обсяг місця. Програма-розподілювач знаходить достатньо велику порожню ділянку в купі, позначає, що вона використовується, і повертає <em>вказівник</em>, тобто адресу цього місця. Цей процес зветься <em>розподілом у купі</em>, що іноді скорочується до простого <em>розподілом</em> (заштовхування значень до стека не вважається розподілом). Оскільки вказівник на купу має відомий, постійний розмір, ви можете зберегти цей вказівник у стеку, але коли вам потрібні дані, вам треба перейти за вказівником. Уявіть собі столи в ресторані. Коли ви входите до ресторану, вам треба сказати кількість людей, що прийшли з вами, тоді офіціант знайде вам порожній стіл, за який всі зможуть сісти, і відведе вас до нього. Якщо хтось спізнився, він зможе спитати, де вас розмістили, щоб приєднатися.</p>
<p>Заштовхування до стека швидше за розподіл у купі, оскільки розподілювачу не треба шукати місце для нових даних, бо це місце завжди є вершиною стека. Розподіл місця у купі вимагає порівняно більше роботи, бо розподілювач має спершу знайти достатньо місця для даних, а потім провести облік місця, щоб приготуватися до наступного розподілу.</p>
<p>Доступ доданих у купі повільніший, ніж у стеку, бо треба переходити за вказівником, щоб дістатися туди. Сучасні процесори швидше працюють, якщо відбувається менше переходів у пам'яті. Розвинемо аналогію: уявімо офіціанта у ресторані, який приймає замовлення з багатьох столів. Найефективніше буде > прийняти всі замовлення з одного столу перед тим, як переходити до наступного. Приймати замовлення зі столу A, потім зі столу B, потім знову з A і знову з B буде значно повільніше. З тієї ж причини процесор краще працює з даними, розташованими поруч (як у стеку), ніж далеко (як може статися в купі).</p>
<p>Коли ваш код викликає функцію, значення, що передаються у функцію (включно з, можливо, вказівниками на дані у купі) і локальні змінні функції заштовхуються у стек. Коли функція завершується, ці значення виштовхуються зі стека.</p>
<p>Відстеження, які частини коду використовують які дані в купі, мінімізація дублювання даних у купі та очищення даних у купі, що вже не потрібні, щоб не скінчилося місце - ось ті завдання, які покликане розв'язати володіння. Коли ви зрозумієте концепцію володіння, вам більше не треба буде постійно думати про стек і купу, але знання, що причина існування володіння - управління даними у купі, допоможе вам зрозуміти, чому воно працює саме так.</p>
</blockquote>
<h3 id="Правила-Володіння"><a class="header" href="#Правила-Володіння">Правила Володіння</a></h3>
<p>По-перше, познайомимося із правилами володіння. Тримайте ці правила на увазі, поки ми працюватимемо із прикладами, що їх ілюструють:</p>
<ul>
<li>Кожне значення в Rust має <em>власника</em>.</li>
<li>У кожен момент може бути лише один власник.</li>
<li>Коли власник виходить зі зони видимості, значення буде скинуто.</li>
</ul>
<h3 id="Область-Видимості-Змінної"><a class="header" href="#Область-Видимості-Змінної">Область Видимості Змінної</a></h3>
<p>Тепер, оскільки ми вже знайомі з основами синтаксису Rust, більше не будемо включати всі ці <code>fn main() {</code> у приклади, тому, щоб випробувати їх, вам доведеться помістити ці приклади до функції <code>main</code> самостійно. Завдяки цьому приклади стануть лаконічнішими і дозволять зосередитися на важливих деталях, а не на шаблонному коді.</p>
<p>У першому прикладі володіння ми розглянемо <em>область видимості</em> деяких змінних. Область видимості - це фрагмент програми, в якому з елементом можна працювати. Нехай ми маємо ось таку змінну:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let s = "hello";
<span class="boring">}
</span></code></pre></pre>
<p>Змінна <code>s</code> посилається на рядковий літерал, де значення рядка закодовано у текст програми. Зі змінною можна працювати з моменту її проголошення до кінця поточної <em>області видимості</em>. Коментарі у Блоці коду 4-1 підказують, де змінна <code>s</code> доступна.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> { // s is not valid here, it’s not yet declared
let s = "hello"; // s is valid from this point forward
// do stuff with s
} // this scope is now over, and s is no longer valid
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок коду 4-1: Змінна і область видимості, де вона доступна</span></p>
<p>Іншими словами, є два важливі моменти часу:</p>
<ul>
<li>Коли <code>s</code> потрапляє <em>в область видимості</em>, вона стає доступною.</li>
<li>Вона лишається доступною, доки не вийде <em>з області видимості</em>.</li>
</ul>
<p>Поки що стосунки між областями видимості та доступністю змінних такі ж самі, як і в інших мовах програмування. Тепер, спираючися на це розуміння, будемо розвиватися, додавши тип <code>String</code>.</p>
<h3 id="Тип-string"><a class="header" href="#Тип-string">Тип <code>String</code></a></h3>
<p>Щоб проілюструвати правила володіння, нам знадобиться тип даних, складніший за ті, що ми вже розглянули у підрозділі <a href="ch03-02-data-types.html#data-types">“Типи даних”</a><!-- ignore --> Розділу 3. Всі типи даних, які ми розглядали раніше, мають заздалегідь відомий розмір, можуть зберігатися в стеку і виштовхуватися звідти, коли їхня область видимості закінчується, і їх можна швидко і просто скопіювати, щоб зробити новий, незалежний екземпляр, коли інша частина коду потребує використати те саме значення в іншій області видимості. Але тепер ми розглянемо дані, що зберігаються в купі та подивимося, як Rust дізнається, коли ці дані треба вичищати, і тип <code>String</code> є чудовим прикладом.</p>
<p>Ми зосередимося на особливостях <code>String</code>, що стосуються володіння. Ці аспекти також застосовуються до інших складних типів даних, які надає стандартна бібліотека або ви створюєте самі. Ми поговоримо про <code>String</code> більш детально в <a href="ch08-02-strings.html">Розділі 8</a><!-- ignore -->.</p>
<p>Ми вже бачили рядкові літерали, у яких значення рядка закодоване в нашу програму. Рядкові літерали зручні, але не завжди підходять для різних ситуацій, де виникає потреба скористатися текстом. Одна з причин полягає в тому, що вони є сталими. Інша - що не кожне значення рядка є відомим під час написання коду: наприклад, як взяти те, що ввів користувач, і зберегти його? Для цих ситуацій, Rust має другий рядковий тип, <code>String</code>. Цей тип керує даними, розподіленими в купі й, відтак, може зберігати текст, обсяг якого невідомий під час компіляції. Можна створити <code>String</code> з рядкового літерала за допомогою функції <code>from</code>, ось так:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let s = String::from("hello");
<span class="boring">}
</span></code></pre></pre>
<p>Оператор подвійна двокрапка <code>::</code> дозволяє доступ до простору імен, що надає нам можливість використати, в цьому випадку, функцію <code>from</code> з типу <code>String</code>, щоб не довелося використовувати назву на кшталт <code>string_from</code>. Цей синтаксис детальніше обговорюється у підрозділі <a href="ch05-03-method-syntax.html#method-syntax">“Синтакис методів”</a><!-- ignore --> Розділу 5 і в обговоренні просторів імен в модулях у <a href="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html">“Способи звертання до елементу в модульному дереві”</a><!-- ignore --> Розділу 7.</p>
<p>Цей тип рядків <em>може</em> бути зміненим:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let mut s = String::from("hello");
s.push_str(", world!"); // push_str() appends a literal to a String
println!("{}", s); // This will print `hello, world!`
<span class="boring">}
</span></code></pre></pre>
<p>У чому ж різниця? Чому <code>String</code> може бути зміненим, але літерали - ні? Різниця полягає в тому, як ці два типи працюють із пам'яттю.</p>
<h3 id="Память-та-її-Виділення"><a class="header" href="#Память-та-її-Виділення">Пам'ять та її Виділення</a></h3>
<p>У випадку рядкового літерала ми знаємо його вміст під час компіляції, тому текст жорстко заданий прямо у виконуваному файлі, що робить рядкові літерали швидкими і ефективними. Але ці властивості випливають з незмінності літерала. На жаль, ми не можемо розмістити у двійковому файлі по шмату пам'яті для кожного фрагменту тексту, розмір якого ми не знаємо під час компіляції й чий розмір може змінитися під час виконання програми.</p>
<p>Для типу <code>String</code>, задля підтримки несталого шматка тексту, що може зростати, нам потрібно розподілити певну кількість пам'яті в купі, невідому під час компіляції, для зберігання вмісту. Це означає:</p>
<ul>
<li>Пам'ять має бути запитана в розподілювача під час виконання.</li>
<li>Нам потрібен спосіб повернення цієї пам'яті до розподілювача, коли ми закінчили працювати з нашим <code>String</code>.</li>
</ul>
<p>Першу частину робимо ми самі: коли ми викликаємо <code>String::from</code>, її реалізація запитує потрібну пам'ять. Так роблять практично всі мови програмування.</p>
<p>Але друга частина відбувається інакше. У мовах зі <em>збирачем сміття (garbage collector, GC)</em>, саме GC стежить і очищує пам'ять, що більше не використовується, і ми, як програмісти, більше можемо не думати про неї. У більшості мов без GC це наша відповідальність - визначити, яка пам'ять більше не потрібна та викликати код для її повернення, так само як до того ми її запитали. Правильно це робити історично є складною задачею у програмуванні. Якщо ми забудемо, ми змарнуємо пам'ять. Якщо ми це зробимо зарано, ми матимемо некоректну змінну. Якщо ми це зробимо двічі, це теж буде помилкою. Потрібно забезпечити, щоб на кожен <code>розподіл</code> було рівно одне <code>звільнення</code> пам'яті.</p>
<p>Rust іде іншим шляхом: пам'ять автоматично повертається, щойно змінна, що нею володіла, іде з області видимості. Ось версія нашого прикладу з Блоку коду 4-1 із використанням <code>String</code> замість рядкового літерала:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> {
let s = String::from("hello"); // s is valid from this point forward
// do stuff with s
} // this scope is now over, and s is no
// longer valid
<span class="boring">}
</span></code></pre></pre>
<p>Існує точка, де природно можна повернути пам'ять, використану нашим рядком, розподілювачу: коли <code>s</code> іде з області видимості. Коли змінна виходить з області видимості, Rust викликає для нас спеціальну функцію. Ця функція зветься <a href="../std/ops/trait.Drop.html#tymethod.drop"><code>drop</code></a><!-- ignore -->, і саме там автор <code>String</code> може розмістити код для повернення пам'яті. Rust викликає <code>drop</code> автоматично на закриваючій фігурній дужці.</p>
<blockquote>
<p>Примітка: в C++ цей шаблон звільнення ресурсів наприкінці життя об'єкта іноді зветься <em>Отримання ресурсу є ініціалізація (Resource Acquisition Is Initialization, RAII</em>). Функція Rust <code>drop</code> має бути знайома вам, якщо ви користувалися шаблонами RAII.</p>
</blockquote>
<p>Цей шаблон має глибокий вплив на спосіб написання коду Rust. Він наразі може виглядати простим, але поведінка коду може бути неочікуваною у складніших ситуаціях, коли ми працюватимемо із декількома змінними, що використовують дані, розподіленими в купі. Тепер дослідимо деякі з цих ситуацій.</p>
<!-- Old heading. Do not remove or links may break. -->
<p><a id="ways-variables-and-data-interact-move"></a></p>
<h4 id="Взаємодія-Змінних-з-Даними-Переміщення"><a class="header" href="#Взаємодія-Змінних-з-Даними-Переміщення">Взаємодія Змінних з Даними: Переміщення</a></h4>
<p>Різні змінні у Rust можуть взаємодіяти з одними й тими ж даними у різні способи. Подивимося на приклад, що використовує ціле число, у Блоці коду 4-2.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 5;
let y = x;
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок коду 4-2: Присвоєння цілого значення змінної <code>x</code> змінній <code>y</code></span></p>
<p>Ми, мабуть, можемо здогадатися, що робить цей код: "прив'язати значення <code>5</code> до <code>x</code>; потім зробити копію значення у <code>x</code> і прив'язати її до <code>y</code>". Тепер ми маємо дві змінні, <code>x</code> та <code>y</code>, і обидві дорівнюють <code>5</code>. І дійсно це так і відбувається, бо цілі - прості значення із відомим, фіксованим розміром, і ці два значення <code>5</code> заштовхуються у стек.</p>
<p>Тепер подивімося на версію зі <code>String</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let s1 = String::from("hello");
let s2 = s1;
<span class="boring">}
</span></code></pre></pre>
<p>Це виглядає дуже схожим на попередній код, тому ми можемо припустити, що воно працює так само, тобто другий рядок створить копію значення з <code>s1</code> і прив'яже її до <code>s2</code>. Але тут відбувається щось трохи інше.</p>
<p>Поглянемо на Рисунок 4-1, щоб зрозуміти, що відбувається всередині <code>String</code>. <code>String</code> складається з трьох частин, показаних ліворуч: вказівника на пам'ять, що зберігає вміст рядка, довжину та місткість. Цей набір даних зберігається в стеку. Праворуч показана пам'ять у купі, що зберігає вміст.</p>
<p><img alt="Дві таблиці: перша таблиця містить представлення s1 у стеку, що
складається з довжини (5), місткості (5) і вказівника на перше значення
у другій таблиці. Друга таблиця містить побайтове представлення
стрічкових даних у купі." src="img/trpl04-01.svg" class="center"
style="width: 50%;" /></p>
<p><span class="caption">Рисунок 4-1: Представлення в пам'яті <code>String</code> зі значенням <code>"hello"</code>, прив'язаної до <code>s1</code></span></p>
<p>Довжина - це кількість пам'яті, в байтах, що вміст <code>String</code> наразі використовує. Місткість - це загальний обсяг пам'яті в байтах, що <code>String</code> отримала від розподілювача. Різниця між довжиною та місткістю має значення, але не в цьому контексті, тому поки що місткість можна спокійно ігнорувати.</p>
<p>Коли ми присвоюємо значення <code>s1</code> змінній <code>s2</code>, дані <code>String</code> копіюються - тобто копіюється вказівник, довжина і місткість, що знаходяться в стеку. Ми не копіюємо даних у купі, на які посилається вказівник. Іншими словами, представлення даних у пам'яті виглядає як на Рисунку 4-2.</p>
<p><img alt="Три таблиці: таблиці s1 і s2, які представляють ці стрічки у стеку,
відповідно, і обидві вони вказують на одну і ту саму стрічку даних у купі."
src="img/trpl04-02.svg" class="center" style="width: 50%;" /></p>
<p><span class="caption">Рисунок 4-2: Представлення в пам'яті змінної <code>s2</code>, що містить копію вказівника, довжини та місткості з <code>s1</code></span></p>
<p>Представлення <em>не</em> виглядає, як показано на Рисунку 4-3, як було б якби Rust дійсно копіювала також і дані в купі. Якби Rust так робила, операція <code>s2 = s1</code> була б потенційно дуже витратною з точки зору швидкості виконання, якщо в купі було б багато даних.</p>
<p><img alt="Чотири таблиці: дві таблиці, що представляють стекові дані для s1 і s2,
і кожна вказує на власну копію стрічкових даних у купі."
src="img/trpl04-03.svg" class="center" style="width: 50%;" /></p>
<p><span class="caption">Рисунок 4-3: Інша можливість того, що могло б робити <code>s2 = s1</code>, якби Rust копіювала також дані в купі</span></p>
<p>Раніше ми казали, що коли змінна виходить з області видимості, Rust автоматично викликає функцію <code>drop</code> і очищає пам'ять цієї змінної в купі. Але Рисунок 4-2 показує, що обидва вказівники вказують на одне й те саме місце. Це створює проблему: коли <code>s2</code> і <code>s1</code> вийдуть з області видимості, вони удвох спробують звільнити одну й ту саму пам'ять. Це зветься помилкою <em>подвійного звільнення</em>, і ми про неї вже згадували. Звільнення пам'яті двічі може призвести до пошкодження пам'яті, і, потенційно, до вразливостей у безпеці.</p>
<p>Для убезпечення пам'яті після рядка <code>let s2 = s1</code> Rust розглядає змінну <code>s1</code> як більше не коректну. Відтак, Rust тепер не буде нічого звільняти, коли <code>s1</code> вийде з області видимості. Перевірте, що станеться, коли ви спробуєте використати <code>s1</code> після створення <code>s2</code>; це не спрацює:</p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
</span> let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);
<span class="boring">}
</span></code></pre>
<p>Ви отримаєте помилку на кшталт цієї, бо Rust не допускає використання некоректних посилань:</p>
<pre><code class="language-console">$ cargo run
Compiling ownership v0.1.0 (file:///projects/ownership)
error[E0382]: borrow of moved value: `s1`
--> src/main.rs:5:28
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 |
5 | println!("{}, world!", s1);
| ^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0382`.
error: could not compile `ownership` due to previous error
</code></pre>
<p>Якщо ви чули терміни <em>пласка копія</em> та <em>глибока копія</em> (“shallow copy” та “deep copy”), коли працювали з іншими мовами, поняття копіювання вказівника, довжини та місткості без копіювання даних виглядають для вас схожими на пласку копію. Але оскільки Rust також унепридатнює першу змінну, це зветься не пласкою копією, а <em>переміщенням</em>. У цьому прикладі ми кажемо, що <code>s1</code> було <em>переміщено</em> в <code>s2</code>. Що фактично відбувається, показано на Рисунку 4-4.</p>
<p><img alt="Три таблиці: таблиці s1 і s2, які представляють ці стрічки у стеку,
відповідно, і обидві вони вказують на одні й ті самі стрічкові даних у купі.
Таблиця s1 є затемнена, бо s1 більше не є коректним; лише s2 можна використовувати
для доступу до даних у купі." src="img/trpl04-04.svg" class="center" style="width:
50%;" /></p>
<p><span class="caption">Рисунок 4-4: Представлення в пам'яті після унепридатнення <code>s1</code></span></p>
<p>Це розв'язує нашу проблему! Якщо коректним зосталося лише <code>s2</code>, коли воно вийде з області видимості, то саме звільнить пам'ять, і готово.</p>
<p>На додачу, такий дизайн мови неявно гарантує, що Rust ніколи не буде автоматично створювати "глибокі" копії ваших даних. Таким чином, будь-яке <em>автоматичне</em> копіювання може вважатися недорогим з точки зору продуктивності під час виконання.</p>
<!-- Old heading. Do not remove or links may break. -->
<p><a id="ways-variables-and-data-interact-clone"></a></p>
<h4 id="Взаємодія-Змінних-з-Даними-Клонування"><a class="header" href="#Взаємодія-Змінних-з-Даними-Клонування">Взаємодія Змінних з Даними: Клонування</a></h4>
<p>Якщо ми <em>хочемо</em> зробити глибоку копію даних <code>String</code> у купі, а не лише в стеку, ми можемо використати загальний метод, що зветься <code>clone</code>. Синтаксис використання методів буде обговорено в Розділі 5, але оскільки методи є загальною особливістю багатьох мов програмування, ви, швидше за все, вже бачили їх.</p>
<p>Ось приклад застосування методу <code>clone</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
<span class="boring">}
</span></code></pre></pre>
<p>Це чудово працює і явно продукує поведінку, показану на Рисунку 4-3, де дані в купі <em>дійсно</em> копіюються.</p>
<p>Коли ви бачите виклик <code>clone</code>, ви знаєте, що виконується певний визначений код і цей код може коштувати продуктивності. Це візуальний індикатор, що відбувається певна операція.</p>
<h4 id="Стекові-Дані-Копіювання"><a class="header" href="#Стекові-Дані-Копіювання">Стекові Дані: Копіювання</a></h4>
<p>Є ще одна дрібниця, про яку ми ще не говорили. Цей код, що використовує цілі числа, частина якого вже була показана раніше в Блоці коду 4-2, коректно працює:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
<span class="boring">}
</span></code></pre></pre>
<p>But this code seems to contradict what we just learned: we don’t have a call to <code>clone</code>, but <code>x</code> is still valid and wasn’t moved into <code>y</code>.</p>
<p>Причина у тому, що типи на кшталт цілих, що мають відомий розмір часу компіляції, зберігаються повністю в стеку, тому копіювання їхніх значень відбувається швидко. Це означає, що нема підстав запобігати коректності <code>x</code> після створення змінної <code>y</code>. Іншими словами, тут немає різниці між глибокою та пласкою копією, і виклик <code>clone</code> не зробить нічого відмінного від звичайного плаского копіювання, тож можна його не викликати.</p>
<p>Rust має спеціальне позначення, що зветься трейтом <code>Copy</code>, який можна додати до типів на кшталт цілих, що зберігаються в стеку (детальніше трейти обговорюються в <a href="ch10-02-traits.html">Розділі 10</a><!-- ignore -->). Якщо тип реалізовує трейт <code>Copy</code>, змінні, що використовують його не переміщуються, а банально копіюються, що робить їх коректними після присвоєння іншій змінній.</p>
<p>Rust не дозволить позначити тип трейтом <code>Copy</code>, якщо тип, чи якась з його частин, реалізовує<code>трейт`Drop</code>. Якщо тип потребує чогось особливого, коли змінна виходить з області видимості, і ми додаємо позначення <code>Copy</code> до цього типу, ми отримаємо помилку часу компіляції. Щоб дізнатися про те, як додати позначку <code>Copy</code> до вашого типу для реалізації трейта, див. <a href="appendix-03-derivable-traits.html">"Придатні до успадкування трейти"</a><!-- ignore --> у Додатку C.</p>
<p>Тож які типи реалізовують трейт <code>Copy</code>? Можна перевірити документацію до певного типу, щоб бути певним, але загальне правило таке: будь-яка група простих скалярних значень може реалізовувати <code>Copy</code>, і нічого з того, що потребує розподілу пам'яті чи є ресурсом, не є <code>Copy</code>. Ось кілька типів, що реалізовують <code>Copy</code>:</p>
<ul>
<li>Всі цілі типи, на кшталт <code>u32</code>.</li>
<li>Булевий тип, <code>bool</code>, значення якого <code>true</code> та <code>false</code>.</li>
<li>Всі типи з рухомою комою, на кшталт <code>f64</code>.</li>
<li>Символьний тип, <code>char</code>.</li>
<li>Кортежі, якщо вони містять лише типи, що реалізовують <code>Copy</code>. Скажімо, <code>(i32, i32)</code> реалізовує <code>Copy</code>, але <code>(i32, String)</code> - ні.</li>
</ul>
<h3 id="Володіння-та-Функції"><a class="header" href="#Володіння-та-Функції">Володіння та Функції</a></h3>
<p>Механіка передачі значень функції подібна до присвоювання значення змінній. Передача змінної функції є переміщенням чи копією, як і присвоювання. Блок коду 4-7 містить приклад з певними поясненнями, що розкривають, де змінні входять і виходять з області видимості.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let s = String::from("hello"); // s comes into scope
takes_ownership(s); // s's value moves into the function...
// ... and so is no longer valid here
let x = 5; // x comes into scope
makes_copy(x); // x would move into the function,
// but i32 is Copy, so it's okay to still
// use x afterward
} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.
fn makes_copy(some_integer: i32) { // some_integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
</code></pre></pre>
<p><span class="caption">Listing 4-3: Functions with ownership and scope annotated</span></p>
<p>Якби ми спробували використати <code>s</code> після виклику <code>takes_ownership</code>, Rust повідомив би про помилку часу компіляції. Ці статичні перевірки захищають нас від помилок. Спробуйте додати в <code>main</code> код, що використовує <code>s</code> та <code>x</code>, щоб побачити, де їх можна використовувати, а де правила володіння запобігають цьому.</p>
<h3 id="Повернення-Значень-та-Область-Видимості"><a class="header" href="#Повернення-Значень-та-Область-Видимості">Повернення Значень та Область Видимості</a></h3>
<p>Повернення значень також передає володіння. Блок коду 4-4 містить приклад функції, що повертає значення, зі схожими на Блок коду 4-3 поясненнями.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 was moved, so nothing
// happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it
let some_string = String::from("yours"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// This function takes a String and returns one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope
a_string // a_string is returned and moves out to the calling function
}
</code></pre></pre>
<p><span class="caption">Блок коду 4-4: Передача володіння значенням, що повертається</span></p>
<p>Володіння змінними завше дотримується однакової схеми: присвоєння значення іншій змінній переміщує його. Коли змінна, що включає дані в купі, виходять з області видимості, якщо дані не були переміщені у володіння іншої змінної, значення буде очищене викликом <code>drop</code>.</p>
<p>Хоча так код працює, все ж взяття володіння і повернення володіння в кожній функції дещо втомлює. Що, як ми хочемо дозволити функції використати значення, але не брати володіння? Потреба повертати все, що ми передаємо в функції, щоб його можна було знову використовувати, разом із даними, утвореними в результаті роботи функції, дратує.</p>
<p>Можна повертати багато значень кортежем, як показано в Блоці коду 4-5.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}.", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len(); // len() returns the length of a String
(s, length)
}
</code></pre></pre>
<p><span class="caption">Блок коду 4-5: Повернення володіння параметрами</span></p>
<p>Але це б давало забагато ритуальних рухів і зайвої роботи для концепції, що має бути загальновживаною. На щастя для нас, Rust має засіб для використання змінної без передачі володіння, що зветься <em>посиланнями</em>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch04-00-understanding-ownership.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="ch04-02-references-and-borrowing.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="ch04-00-understanding-ownership.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="ch04-02-references-and-borrowing.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>