-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch18-03-pattern-syntax.html
636 lines (562 loc) · 85.7 KB
/
ch18-03-pattern-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
<!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"><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" class="active"><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>
<h3 id="Зіставлення-з-Літералами"><a class="header" href="#Зіставлення-з-Літералами">Зіставлення з Літералами</a></h3>
<p>Як ви бачили у Розділі 6, можна зіставляти шаблони з літералами напряму. Наведемо декілька прикладів в наступному коді:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
<span class="boring">}
</span></code></pre></pre>
<p>Цей код виведе в консолі <code>one</code>, оскільки значення в <code>x</code> дорівнює 1. Цей синтаксис корисний, коли ви хочете, щоб ваш код виконував дію, якщо він отримує певне значення.</p>
<h3 id="Зіставлення-з-Іменованими-Змінними"><a class="header" href="#Зіставлення-з-Іменованими-Змінними">Зіставлення з Іменованими Змінними</a></h3>
<p>Іменовані змінні - це незаперечні шаблони, які відповідають будь-якому значенню, і ми багато разів використовували їх у книзі. Однак, існує ускладнення при використанні іменованих змінних у виразах <code>match</code>. Оскільки <code>match</code> починає нову область видимості, змінні, оголошені як частина шаблону всередині виразу <code>match</code>, будуть затінювати змінні з тією ж назвою за межами конструкції <code>match</code>, як і у випадку з усіма змінними. У Блоці Коду 18-11 оголошується змінна з назвою <code>x</code> зі значенням <code>Some(5)</code> та змінна <code>y</code> зі значенням <code>10</code>. Потім ми створюємо вираз <code>match</code> над значенням <code>x</code>. Подивіться на шаблони в рукавах match і <code>println!</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> let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {y}"),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {y}", x);
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-11: Вираз <code>match</code> з рукавом, що вводить затінену змінну <code>y</code></span></p>
<p>Розглянемо, що відбувається при виконанні виразу <code>match</code>. Шаблон у першому рукаві порівняння не збігається із заданим значенням <code>x</code>, тому код продовжується.</p>
<p>Шаблон у другому рукаві порівняння вводить нову змінну з назвою <code>y</code>, яка буде відповідати будь-якому значенню всередині значення <code>Some</code>. Оскільки ми знаходимося в новій області видимості всередині виразу <code>match</code>, це нова змінна <code>y</code>, а не та <code>y</code>, яку ми оголосили на початку зі значенням 10. Ця нова прив'язка <code>y</code> буде відповідати будь-якому значенню всередині <code>Some</code>, яке ми маємо в <code>x</code>. Таким чином, ця нова <code>y</code> зв'язується з внутрішнім значенням <code>Some</code> в <code>x</code>. Це значення <code>5</code>, тому вираз для цього рукава виконується і виводить в консолі <code>Matched, y = 5</code>.</p>
<p>Якби значення <code>x</code> було б <code>None</code> замість <code>Some(5)</code>, шаблони в перших двох рукавах не збіглися б, тому значення збіглося б з підкресленням. Ми не створювали змінну <code>x</code> у шаблоні підкреслення, тому <code>x</code> у виразі - це все ще зовнішній <code>x</code>, який не був затінений. У цьому гіпотетичному випадку <code>match</code> виведе в консолі <code>Default case, x = None</code>.</p>
<p>Коли вираз <code>match</code> виконано, його область видимості закінчується, так само як і область видимості внутрішньої <code>y</code>. Останній <code>println!</code> виведе в консолі <code>at the end: x = Some(5), y = 10</code>.</p>
<p>Щоб створити вираз <code>match</code>, який порівнює значення зовнішніх <code>x</code> і <code>y</code>, замість того, щоб вводити затінену змінну, нам потрібно буде використовувати умовний запобіжник. Ми поговоримо про запобіжники пізніше в розділі <a href="#extra-conditionals-with-match-guards">"Додаткові умови з запобіжниками"</a><!--
ignore --> .</p>
<h3 id="Декілька-Шаблонів"><a class="header" href="#Декілька-Шаблонів">Декілька Шаблонів</a></h3>
<p>У виразах <code>match</code> ви можете зіставляти кілька шаблонів, використовуючи синтаксис <code>|</code>, який є оператором шаблону <em>or</em>. Наприклад, у наступному коді ми порівнюємо значення <code>x</code> з рукавами match, перше з яких має опцію <em>or</em>, що означає, що якщо значення <code>x</code> збігається з будь-яким зі значень у цьому рукаві, код цього рукава буде виконано:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
<span class="boring">}
</span></code></pre></pre>
<p>Цей код виведе в консоль <code>one or two</code>.</p>
<h3 id="Зіставлення-Діапазонів-Значень-з-"><a class="header" href="#Зіставлення-Діапазонів-Значень-з-">Зіставлення Діапазонів Значень з <code>..=</code></a></h3>
<p>Синтаксис <code>..=</code> дозволяє робити інклюзивне зіставлення, зіставлення з діапазоном включно з останнім його значенням. В наступному коді буде виконана гілка, шаблон якої зіставляється з будь-яким значенням заданого діапазону:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
<span class="boring">}
</span></code></pre></pre>
<p>Якщо <code>x</code> дорівнює 1, 2, 3, 4, або 5, то буде обрана перша гілка виразу match. Цей синтаксис більш зручний для зіставлення декількох значень ніж використання оператора <code>|</code> для вираження тої самої ідеї; якщо ми використовували б <code>|</code>, нам було б потрібно вказати <code>1 | 2 | 3 | 4 | 5</code>. Вказання діапазону набагато коротше, особливо якщо ми хочемо зіставляти, скажімо, будь-яке число між 1 та 1,000!</p>
<p>Компілятор перевіряє, що діапазон не порожній під час компіляції, і оскільки єдиними типами, для яких Rust може сказати, чи є діапазон порожнім чи ні, є <code>char</code> та числові значення, діапазони дозволяють лише числові або <code>char</code> значення.</p>
<p>Ось приклад використання діапазонів значень <code>char</code>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 'c';
match x {
'a'..='j' => println!("early ASCII letter"),
'k'..='z' => println!("late ASCII letter"),
_ => println!("something else"),
}
<span class="boring">}
</span></code></pre></pre>
<p>Rust може визначити, що <code>'c'</code> в першому діапазоні шаблона та виведе в консоль <code>early ASCII letter</code>.</p>
<h3 id="Деструктурування-для-Розбору-Значень-на-Частини"><a class="header" href="#Деструктурування-для-Розбору-Значень-на-Частини">Деструктурування для Розбору Значень на Частини</a></h3>
<p>Ми також використовуємо шаблони для деструктуризації структур, енумів та кортежів для використання різних частин їх значень. Розглянемо покроково кожне значення.</p>
<h4 id="Деструктурування-Структур"><a class="header" href="#Деструктурування-Структур">Деструктурування Структур</a></h4>
<p>У Блоці Коду 18-12 показана структура <code>Point</code> з двома полями <code>x</code> і <code>y</code>, яку ми можемо розбити на частини за допомогою шаблону з інструкцією <code>let</code>.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-12: Деструктуризація полів структури в окремі змінні</span></p>
<p>В цьому коді створюються змінні <code>a</code> та <code>b</code>, які відповідають значенням полів <code>x</code> та <code>y</code> структури <code>p</code>. Цей приклад показує, що назви змінних у шаблоні не обов'язково повинні збігатися з назвами полів структури. Однак, зазвичай назви змінних збігаються з назвами полів, щоб полегшити запам'ятовування того, які змінні походять з яких полів. Через таке поширене використання, а також через те, що запис <code>let Point { x: x, y: y } = p;</code> містить багато повторень, Rust має скорочення для шаблонів, які відповідають полям struct: вам потрібно лише перерахувати назву поля struct, і змінні, створені на основі шаблону, матимуть ті ж самі назви. Блок Коду 18-13 працює так само як і Блок Коду 18-12, але змінні, що створюються в шаблоні <code>let</code>, є <code>x</code> і <code>y</code> замість <code>a</code> і <code>b</code>.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
assert_eq!(0, x);
assert_eq!(7, y);
}
</code></pre></pre>
<p><span class="caption">Блок коду 18-13: Деструктуризація полів структури за допомогою скорочення</span></p>
<p>Цей код створить змінні <code>x</code> та <code>y</code>, які відповідають полям <code>x</code> та<code>y</code> змінної <code>p</code>. В результаті змінні <code>x</code> та <code>y</code> містять значення зі структури <code>p</code>.</p>
<p>Ми також можемо деструктурувати за допомогою буквених значень як частини шаблону struct замість того, щоб створювати змінні для всіх полів. Це дозволяє нам перевіряти деякі з полів на наявність певних значень, створюючи змінні для деструктуризації інших полів.</p>
<p>У Блоці Коду 18-14 ми маємо вираз <code>match</code>, який розділяє значення <code>Point</code> на три випадки: точки, які лежать безпосередньо на осі <code>x</code> (що вірно, коли <code>y = 0</code>), на осі <code>y</code> (<code>x = 0</code>), або не лежать ні на одній з них.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">struct Point {
</span><span class="boring"> x: i32,
</span><span class="boring"> y: i32,
</span><span class="boring">}
</span><span class="boring">
</span>fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the x axis at {x}"),
Point { x: 0, y } => println!("On the y axis at {y}"),
Point { x, y } => {
println!("On neither axis: ({x}, {y})");
}
}
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-14: Деструктуризація та зіставлення буквених значень в одному шаблоні</span></p>
<p>Перший рукав буде відповідати будь-якій точці, що лежить на осі <code>x</code>, вказуючи, що поле <code>y</code> збігається, якщо його значення збігається з <code>0</code>. Шаблон все ще створює змінну <code>x</code>, яку ми можемо використовувати в коді для цього рукава.</p>
<p>Аналогічно, другий рукав зіставляє будь-яку точку на осі <code>y</code>, вказуючи, що поле <code>x</code> збігається, якщо його значення дорівнює <code>0</code>, і створює змінну <code>y</code> для значення поля <code>y</code>. Третій рукав не визначає ніяких літералів, тому воно відповідає будь-якій іншій <code>Point</code> і створює змінні для полів <code>x</code> і <code>y</code>.</p>
<p>У цьому прикладі значення <code>p</code> збігається з другим рукавом, оскільки <code>x</code> містить 0, тому цей код виведе в консолі <code>On the y axis at 7</code>.</p>
<p>Пам'ятайте, що вираз <code>match</code> припиняє перевірку рукавів після того, як знайде перший збіг, тому навіть якщо <code>Point { x: 0, y: 0}</code> знаходиться як на осі <code>x</code>, так і на осі <code>y</code>, цей код виведе в консолі <code>On the x axis at 0</code>.</p>
<h4 id="Деструктурування-Енумів"><a class="header" href="#Деструктурування-Енумів">Деструктурування Енумів</a></h4>
<p>У цій книзі ми вже деструктурували енуми (наприклад, в Блоці Коду 6-5 Розділу 6), але ми ще окремо не обговорювали, що шаблон деструктурування енума повинен відповідати тому, як визначаються збережені в енумі дані. Як приклад, у Блоці Коду 18-15 ми використовуємо енум <code>Message</code> з Блоку Коду 6-2 і пишемо <code>match</code> з шаблонами, які деструктуруватимуть кожне внутрішнє значення.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => {
println!("The Quit variant has no data to destructure.");
}
Message::Move { x, y } => {
println!("Move in the x direction {x} and in the y direction {y}");
}
Message::Write(text) => {
println!("Text message: {text}");
}
Message::ChangeColor(r, g, b) => {
println!("Change the color to red {r}, green {g}, and blue {b}",)
}
}
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-15: Деструктурування варіантів енума, що містять різні види значень</span></p>
<p>Цей код виведе в консолі <code>Change the color to red 0, green 160, and blue 255</code>. Спробуйте змінити значення <code>msg</code>, щоб побачити виконання коду з інших рукавів.</p>
<p>Для варіантів енуму без даних, таких як <code>Message::Quit</code>, ми не можемо деструктурувати значення далі. Ми тільки можемо зіставити буквальне значення <code>Message::Quit</code>, і жодних змінних у цьому шаблоні немає.</p>
<p>Для структуро-подібних варіантів енуму, таких як <code>Message::Move</code>, ми можемо використовувати шаблон схожий з тим, що ми вказували для зіставлення структур. Після назви варіанту ми ставимо фігурні дужки, а потім перелічуємо поля зі змінними, щоб розбити все на частини, які будуть використані в коді для цього рукава. Тут ми використовуємо скорочену форму, як ми це робили в Блоці Коду 18-13.</p>
<p>Шаблони кортежо-подібних варіантів енума, таких як <code>Message::Write</code>, що містить кортеж з одним елементом, і <code>Message::ChangeColor</code>, що містить кортеж з трьома елементами подібні до шаблону, який ми вказуємо для зіставлення кортежів. Кількість змінних у шаблоні повинна відповідати кількості елементів у варіанті, який ми порівнюємо.</p>
<h4 id="Деструктурування-Вкладених-Структур-та-Енумів"><a class="header" href="#Деструктурування-Вкладених-Структур-та-Енумів">Деструктурування Вкладених Структур та Енумів</a></h4>
<p>Дотепер всі наші приклади стосувалися зіставлення структур або енумів глибиною в один рівень, але зіставлення може працювати і на вкладених елементах! Наприклад, ми можемо переробити код у Блоці Коду 18-15 для додавання підтримки RGB та HSV кольорів у повідомленні <code>ChangeColor</code>, як показано у Блоці Коду 18-16.</p>
<pre><pre class="playground"><code class="language-rust">enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!("Change color to red {r}, green {g}, and blue {b}");
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("Change color to hue {h}, saturation {s}, value {v}")
}
_ => (),
}
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-16: Зіставлення з вкладеними енумами</span></p>
<p>Шаблон першого рукава у виразі <code>match</code> відповідає варіанту енуму <code>Message::ChangeColor</code>, який містить варіант <code>Color::Rgb</code>; потім шаблон зв'язується з трьома внутрішніми значеннями <code>i32</code>. Шаблон другого рукава також відповідає варіанту енуму <code>Message::ChangeColor</code>, але внутрішній енум замість цього збігається з <code>Color::Hsv</code>. Ми можемо вказувати такі складні умови в одному виразі <code>match</code>, навіть якщо залучені два енуми.</p>
<h4 id="Деструктурування-Структур-та-Кортежів"><a class="header" href="#Деструктурування-Структур-та-Кортежів">Деструктурування Структур та Кортежів</a></h4>
<p>Ми можемо змішувати, зіставляти та вкладати деструктуризуючі шаблони і складнішими способами. В наступному прикладі показано складна деструктуризація, де ми вкладаємо структури та кортежі в кортеж та деструктуризуємо все примітивні значення:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span><span class="boring"> struct Point {
</span><span class="boring"> x: i32,
</span><span class="boring"> y: i32,
</span><span class="boring"> }
</span><span class="boring">
</span> let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
<span class="boring">}
</span></code></pre></pre>
<p>Цей код дозволяє нам розбивати складні типи на складові частини, щоб ми могли окремо використовувати потрібні нам значення.</p>
<p>Деструктуризація за допомогою шаблонів є зручним способом використання фрагментів значень, таких як значення з кожного поля в структурі, окремо один від одного.</p>
<h3 id="Ігнорування-Значень-Шаблону"><a class="header" href="#Ігнорування-Значень-Шаблону">Ігнорування Значень Шаблону</a></h3>
<p>Ви бачили, що іноді корисно ігнорувати значення в шаблоні, наприклад в останньому рукаві <code>match</code>, щоб отримати загальний шаблон, який не робить деструктуризації, але враховує всі можливі значення, що залишилися. Існує декілька способів ігнорувати цілі значення або частини значень у шаблоні: використання шаблону <code>_</code> (який ви вже бачили), використання шаблону <code>_</code> всередині іншого шаблону, використання імені, яке починається з символу підкреслення, або використання <code>..</code> для ігнорування решти частини значення. Розглянемо, як і навіщо використовувати кожен з цих шаблонів.</p>
<h4 id="Ігнорування-Всього-Значення-з-_"><a class="header" href="#Ігнорування-Всього-Значення-з-_">Ігнорування Всього Значення з <code>_</code></a></h4>
<p>Ми використали символ підкреслення як загальний шаблон, який буде відповідати будь-якому значенню, але не прив'язуватиметься до нього. Це особливо корисно як останній рукав виразу <code>match</code>, але ми також можемо використовувати його в будь-якому шаблоні, включно з параметрами функцій, як показано в Блоці Коду 18-17.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn foo(_: i32, y: i32) {
println!("This code only uses the y parameter: {}", y);
}
fn main() {
foo(3, 4);
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-17: Використання <code>_</code> в сигнатурі функції</span></p>
<p>Цей код повністю проігнорує значення <code>3</code>, передане першим аргументом, і виведе <code>Даний код використовує тільки y параметр: 4</code>.</p>
<p>У більшості випадків, коли вам більше не потрібен певний параметр функції, ви змінили б підпис так, щоб він не включав невикористаний параметр. Ігнорування параметру функції може бути особливо корисним у випадках, коли, наприклад, ви реалізуєте трейт і вам потрібна сигнатура певного типу, але тіло функції у вашій реалізації не потребує жодного з параметрів. Ви тоді уникаєте попередження компілятора про невикористані параметри функції, яке було б у випадку використання назви.</p>
<h4 id="Ігнорування-Частин-Значення-з-Вкладеним-_"><a class="header" href="#Ігнорування-Частин-Значення-з-Вкладеним-_">Ігнорування Частин Значення з Вкладеним <code>_</code></a></h4>
<p>Ми також можемо використовувати <code>_</code> всередині іншого шаблону, щоб ігнорувати тільки частину значення, наприклад, коли ми хочемо перевірити тільки частину значення, але не використовуємо інші частини у відповідному коді, який ми хочемо виконати. У Блоці Коду 18-18 наведено код що відповідає за керування значенням налаштувань. Бізнес-вимоги полягають в тому, що користувачеві не повинно бути дозволено перезаписувати існуюче задане налаштування, але користувач може скасувати налаштування та надати йому значення, якщо воно наразі не задане.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let mut setting_value = Some(5);
let new_setting_value = Some(10);
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
println!("Can't overwrite an existing customized value");
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {:?}", setting_value);
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-18: Використання підкреслення всередині шаблонів, які відповідають варіантам <code>Some</code>, коли нам не потрібно використовувати значення всередині <code>Some</code> варіанту</span></p>
<p>Цей код виведе <code>Неможливо перезаписати існуюче користувацьке значення</code>, а потім <code>налаштування це Some(5)</code>. У першому рукаві match нам не потрібно зіставляти або використовувати значення всередині будь-якого з варіантів <code>Some</code>, але нам потрібно перевірити випадок, коли <code>setting_value</code> і <code>new_setting_value</code> є варіантом <code>Some</code>. У цьому випадку ми виводимо причину незмінності <code>setting_value</code>, і воно не зміниться.</p>
<p>У всіх інших випадках (якщо або <code>setting_value</code>, або <code>new_setting_value</code> є <code>None</code>), виражених шаблоном <code>_</code> у другому плечі, ми хочемо дозволити <code>new_setting_value</code> стати <code>setting_value</code>.</p>
<p>Ми також можемо використовувати підкреслення в декількох місцях в межах одного шаблону, щоб ігнорувати певні значення. У Блоку Коду 18-19 наведено приклад ігнорування другого та четвертого значень у кортежі з п'яти елементів.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {first}, {third}, {fifth}")
}
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-19: Ігнорування кількох частин кортежу</span></p>
<p>Цей код виведе <code>Деякі числа: 2, 8, 32</code>, а значення 4 та 16 будуть проігноровані.</p>
<h4 id="Ігнорування-Невикористаної-Змінної-Починаючи-Її-Назву-з-_"><a class="header" href="#Ігнорування-Невикористаної-Змінної-Починаючи-Її-Назву-з-_">Ігнорування Невикористаної Змінної, Починаючи Її Назву з <code>_</code></a></h4>
<p>Якщо ви створюєте змінну, але ніде її не використовуєте, Rust зазвичай попередить про це, оскільки невикористана змінна може бути помилкою. Однак, іноді буває корисно мати можливість створити змінну, яку ви поки що не будете використовувати, наприклад, коли ви створюєте прототип або тільки починаєте проєкт. У цій ситуації ви можете заборонити Rust попереджати вас про невикористану змінну, почавши назву змінної з символу підкреслення. У Боку Коду 18-20 ми створюємо дві невикористовувані змінні, але при компіляції цього коду ми повинні отримати попередження лише про одну з них.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let _x = 5;
let y = 10;
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-20: Початок назви змінної з символу підкреслення, щоб уникнути попередження про невикористані змінні</span></p>
<p>Тут ми отримуємо попередження про невикористання змінної <code>y</code>, але не отримуємо попередження про невикористання <code>_x</code>.</p>
<p>Зверніть увагу, що існує тонка різниця між використанням тільки <code>_</code> і використанням імені яке починається з підкреслення. Синтаксис <code>_x</code> все ще прив'язує значення до змінної тоді як <code>_</code> не прив'язує взагалі. Щоб показати випадок, коли ця відмінність має значення, в Блоці Коду 18-21 ми наведемо помилку.</p>
<pre><code class="language-rust ignore does_not_compile"><span class="boring">fn main() {
</span> let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{:?}", s);
<span class="boring">}
</span></code></pre>
<p><span class="caption">Блок Коду 18-21: Невикористана змінна, що починається з підкреслення все ще прив'язує значення, що може отримати над ним володіння</span></p>
<p>Ми отримаємо помилку, тому що значення <code>s</code> однаково буде переміщено в <code>_s</code>, що не дозволить нам використовувати <code>s</code> знову. Однак, використання символу підкреслення самого по собі ніколи не призведе до прив'язки до значення. Блок Коду 18-22 скомпілюється без помилок тому що <code>s</code> не переміщується в <code>_</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{:?}", s);
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-22: Використання символу підкреслення не прив'язує значення</span></p>
<p>Цей код працює, оскільки ми ніколи та ні до чого не прив'язували <code>s</code>; воно не зміщене.</p>
<h4 id="Ігнорування-Решти-Частин-Значення-з-"><a class="header" href="#Ігнорування-Решти-Частин-Значення-з-">Ігнорування Решти Частин Значення з <code>..</code></a></h4>
<p>Для значень, які мають багато частин, ми можемо використовувати синтаксис <code>..</code>, щоб використовувати певні частини та ігнорувати решту, уникаючи необхідності підкреслення кожного ігнорованого значення. Шаблон <code>..</code> ігнорує будь-які частини значення, які ми не зіставили явно в інших частинах шаблону. У Блоці Коду 18-23 ми маємо структуру <code>Point</code>, яка зберігає координату в тривимірному просторі. У виразі <code>match</code> ми хочемо оперувати тільки координатою <code>x</code> і ігнорувати значення в полях <code>y</code> та <code>z</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point { x, .. } => println!("x is {}", x),
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-23: Ігнорування всіх полів <code>Point</code> крім для <code>x</code> з використанням <code>..</code></span></p>
<p>Ми перераховуємо значення <code>x</code>, а потім просто додаємо шаблон <code>..</code>. Це швидше. ніж перераховувати <code>y: _</code> і <code>z: _</code>, особливо коли ми працюємо зі структурами, які мають багато полів, в ситуаціях, коли тільки одне або два поля є релевантними.</p>
<p>Синтаксис <code>..</code> буде поширюватися на стільки значень, скільки потрібно. У Блоці Коду 18-24 показано, як використовувати <code>..</code> з кортежем.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("Some numbers: {first}, {last}");
}
}
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-24: Порівняння тільки першого та останнього значень кортежу та ігнорування усіх інших значень</span></p>
<p>У цьому коді першому та останньому значенню відповідають <code>first</code> та <code>last</code>. <code>..</code> буде зіставлятися та ігнорувати зі всім посередині.</p>
<p>Однак використання <code>..</code> має бути однозначним. Якщо незрозуміло, які значення призначені для зіставлення, а які слід ігнорувати, Rust видасть помилку. У Блоці Коду 18-25 наведено приклад неоднозначного використання <code>..</code>, тому він не буде компілюватися.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><code class="language-rust ignore does_not_compile">fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(.., second, ..) => {
println!("Some numbers: {}", second)
},
}
}
</code></pre>
<p><span class="caption">Блок Коду 18-25: Спроба використання <code>..</code> неоднозначним способом</span></p>
<p>Якщо ми скомпілюємо цей приклад, ми отримаємо цю помилку:</p>
<pre><code class="language-console">$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error: `..` can only be used once per tuple pattern
--> src/main.rs:5:22
|
5 | (.., second, ..) => {
| -- ^^ can only be used once per tuple pattern
| |
| previously used here
error: could not compile `patterns` due to previous error
</code></pre>
<p>Rust не може визначити, скільки значень у кортежі слід ігнорувати, перш ніж знайти значення з <code>second</code>, а потім скільки наступних значень слід ігнорувати після цього. Цей код може означати, що ми хочемо ігнорувати <code>2</code>, пов'язати <code>second</code> з <code>4</code>, а потім ігнорувати <code>8</code>, <code>16</code> та <code>32</code>; або що ми хочемо ігнорувати <code>2</code> і <code>4</code>, зв'язати <code>second</code> з <code>8</code>, а потім ігнорувати <code>16</code> і <code>32</code>; тощо. Назва змінної <code>second</code> нічого особливого для Rust не означає, тому ми отримуємо помилку компілятора, тому що використання <code>..</code> в двох таких місцях є неоднозначним.</p>
<h3 id="Додаткові-Умови-з-Запобіжниками-Зіставлення"><a class="header" href="#Додаткові-Умови-з-Запобіжниками-Зіставлення">Додаткові Умови з Запобіжниками Зіставлення</a></h3>
<p><em>Запобіжник match</em> є додатковою умовою <code>if</code>, зазначеною після шаблону в рукаві <code>match</code>, яка також повинна збігатися для того, щоб цей рукав було обрано. Запобіжники match корисні для вираження складніших ідей, ніж дозволяє один тільки шаблон.</p>
<p>В умові можуть використовуватись змінні, створені в шаблоні. У Блоці Коду 18-26 показано <code>match</code>, де перший рукав має шаблон <code>Some(x)</code>, а також має запобіжник match <code>if x % 2 == 0</code> (що буде істинним, якщо число парне).</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let num = Some(4);
match num {
Some(x) if x % 2 == 0 => println!("The number {} is even", x),
Some(x) => println!("The number {} is odd", x),
None => (),
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-26: Додавання запобіжника зіставлення до шаблона</span></p>
<p>Цей приклад виведе в консолі <code>The number 4 is even</code>. Коли <code>num</code> порівнюється з у першому рукаві, вони збігаються, оскільки <code>Some(4)</code> збігається з <code>Some(x)</code>. Потім запобіжник match перевіряє, чи залишок від ділення <code>x</code> на 2 дорівнює 0, і якщо це так, то вибирається перший рукав.</p>
<p>Якби замість <code>num</code> було <code>Some(5)</code>, то запобіжник match у першому рукаві був би хибним, оскільки остача від ділення 5 на 2 дорівнює 1, що не дорівнює 0. Rust потім перейде до другого рукава, який збігатиметься, тому що другий рукав не має запобіжника match і тому збігається з будь-яким варіантом <code>Some</code>.</p>
<p>Немає можливості виразити умову <code>if x % 2 == 0</code> в шаблоні, тому запобіжник дає можливість виразити цю логіку. Недоліком цієї додаткової виразності є те, що компілятор не намагатиметься перевіряти на вичерпність, коли задіяні вирази запобіжнику match.</p>
<p>У Блоці Коду 18-11 ми згадували, що могли б використовувати запобіжники match для вирішення нашої проблему тінізації шаблонів. Нагадаємо, що ми створили нову змінну всередині шаблону у виразі <code>match</code> замість того, щоб використовувати змінну за межами <code>match</code>. Ця нова змінна означала, що ми не могли перевіряти значення зовнішньої змінної. У Блоці Коду 18-27 показано, як ми можемо використовувати запобіжник match, щоб розв'язати цю проблему.</p>
<p><span class="filename">Файл: src/main.rs</span></p>
<pre><pre class="playground"><code class="language-rust">fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(n) if n == y => println!("Matched, n = {n}"),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {y}", x);
}
</code></pre></pre>
<p><span class="caption">Блок Коду 18-27: Використання запобіжника match для перевірки рівності із зовнішньою змінною</span></p>
<p>Цей код виведе в консолі <code>Default case, x = Some(5)</code>. Шаблон у другому рукаві збігу не вводить нову змінну <code>y</code>, яка б затінювала зовнішню <code>y</code>, що означає, що ми можемо використовувати зовнішню <code>y</code> у запобіжнику match. Замість того, щоб вказати шаблон як <code>Some(y)</code>, що затінило б зовнішнє <code>y</code>, ми вказуємо <code>Some(n)</code>. Це створює нову змінну <code>n</code>, яка нічого не затінює, оскільки немає змінної <code>n</code> за межами <code>match</code>.</p>
<p>Запобіжник match <code>if n == y</code> не є шаблоном і тому не вводить нових змінних. Цей <code>y</code> <em>дорівнює</em> зовнішньому <code>y</code>, а не новому затіненому <code>y</code>, і ми можемо шукати значення, яке має те саме значення, що й зовнішнє <code>y</code>, порівнюючи <code>n</code> з <code>y</code>.</p>
<p>Ви також можете використовувати <em>or</em> оператор <code>|</code> в запобіжнику match для вказування декількох шаблонів; умова запобіжнику match буде застосовуватися до всіх шаблонів. У Блоці Коду 18-28 показано черговість при об'єднанні шаблону, який використовує <code>|</code> з запобіжником match. Важливою частиною цього прикладу є те, що запобіжник match <code>if y</code> застосовується до <code>4</code>, <code>5</code>, <em>та</em> <code>6</code>, хоча це може виглядати як <code>if y</code> тільки застосовується лише до <code>6</code>.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"),
_ => println!("no"),
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок Коду 18-28: Об'єднання декількох шаблонів за допомогою запобіжнику match</span></p>
<p>Умова match вказує, що рукав збігається, тільки якщо значення <code>x</code> дорівнює <code>4</code>, <code>5</code> або <code>6</code> <em>та</em> якщо <code>y</code> дорівнює <code>true</code>. При виконанні цього коду шаблон першого рукава збігається, оскільки <code>x</code> дорівнює <code>4</code>, але запобіжник збігу <code>if y</code> є хибним, тому перший рукав не обирається. Код переходить на другий рукав, який збігається, і ця програма виводить в консолі <code>no</code>. Причина в тому, що умова <code>if</code> застосовується до всього шаблону <code>4 | 5 | 6</code>, а не тільки до останнього значення <code>6</code>. Іншими словами, черговість запобіжнику match відносно шаблону наступна:</p>
<pre><code class="language-text">(4 | 5 | 6) if y => ...
</code></pre>
<p>замість:</p>
<pre><code class="language-text">4 | 5 | (6 if y) => ...
</code></pre>
<p>Після виконання коду, поведінка пріоритету очевидна: якби запобіжник match був застосований тільки до кінцевого значення в списку значень, заданих з допомогою оператора <code>|</code>, то рукав збігся б і програма вивела б <code>yes</code>.</p>
<h3 id="-Звязування"><a class="header" href="#-Звязування"><code>@</code> Зв'язування</a></h3>
<p><code>@</code>, що вимовляється "оператор <em>at</em>", дозволяє нам створити змінну, яка містить значення, у той час, коли ми перевіряємо значення на відповідність шаблону. У Блоці коду 18-29 ми хочемо перевірити, що поле <code>id</code> у <code>Message::Hello</code> є в межах <code>3..=7</code>. Ми також хочемо зв'язати значення зі змінною <code>id_variable</code>, щоб ми могли використати її у коді рукава. Ми могли назвати цю змінну <code>id</code>, так само як і поле, але для цього прикладу ми використаємо іншу назву.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">fn main() {
</span> enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..=7,
} => println!("Found an id in range: {}", id_variable),
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => println!("Found some other id: {}", id),
}
<span class="boring">}
</span></code></pre></pre>
<p><span class="caption">Блок коду 18-29: використання <code>@</code> для зв'язування зі значенням у шаблоні і водночас перевірки</span></p>
<p>Цей приклад виведе в консолі <code>Found an id in range: 5</code>. Зазначивши <code>id_variable @</code> перед інтервалом <code>3..=7</code> ми захоплюємо будь-яке значення, що відповідає інтервалу, перевіряючи при цьому, що значення відповідає шаблону.</p>
<p>У другому рукаві, де є лише інтервал, зазначений у шаблоні, код, асоційований з цим рукавом, не має змінної, яка містила б фактичне значення поля <code>id</code>. Значення поля <code>id</code> могло б бути 10, 11, або 12, але код, що йде з цим шаблоном, не знає, яким воно є. Код шаблону нездатний використати значення поля <code>id</code>, оскільки ми не зберегли значення <code>id</code> у змінній.</p>
<p>В останньому рукаві, де ми вказали змінну без інтервалу, ми маємо значення, доступне для використання в коді рукава, в змінній з назвою <code>id</code>. Це тому, що ми скористалися скороченим синтаксисом поля структури. Але ми не застосували жодної перевірки для поля <code>id</code> у цьому рукаві, як робили у двох перших рукавах: будь-яке значення відповідає цьому шаблону.</p>
<p>Використання <code>@</code> дозволяє нам перевірити значення і зберегти його в змінній в одному шаблоні.</p>
<h2 id="Підсумок"><a class="header" href="#Підсумок">Підсумок</a></h2>
<p>Шаблони в Rust дуже корисні для розрізнення між різновидами даних. При використанні у виразах <code>match</code> Rust гарантує, що ваші шаблони покривають усі можливі значення, бо інакше ваша програма не скомпілюється. Шаблони в інструкціях <code>let</code> і параметрах функцій роблять ці конструкції кориснішими, дозволяючи деструктуризацію значень на менші частини одночасно з що присвоєнням їх змінним. Ми можемо створювати прості або складні шаблони відповідно до наших потреб.</p>
<p>Далі, у передостанньому розділі книжки ми подивимося на деякі розширені аспекти низки функціоналів Rust.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ch18-02-refutability.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="ch19-00-advanced-features.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="ch18-02-refutability.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="ch19-00-advanced-features.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>