Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Додаток C: Трейти, що можна виводити

У різних місцях у книзі ми обговорювали атрибут derive, який ви можете застосувати до визначення структури або переліку. Атрибут derive генерує код, який реалізує трейт із власною реалізацією за замовчуванням на типі, який ви анотували синтаксисом derive.

У цьому додатку ми надаємо довідку для всіх трейтів у стандартній бібліотеці, які ви можете використовувати з derive. Кожен розділ охоплює:

  • Які оператори та методи стане можливим використовувати завдяки виведенню цього трейту
  • Що робить реалізація трейту, надана derive
  • Що означає реалізація трейту щодо типу
  • Умови, за яких вам дозволено або не дозволено реалізовувати трейт
  • Приклади операцій, які потребують трейт

Якщо ви хочете іншу поведінку, ніж та, що надається атрибутом derive, зверніться до документації стандартної бібліотеки для кожного трейту, щоб дізнатися подробиці про те, як реалізувати їх вручну.

Трейти, перелічені тут, — це єдині визначені стандартною бібліотекою, які можна реалізувати на ваших типах за допомогою derive. Інші трейт, визначені у стандартній бібліотеці, не мають розумної поведінки за замовчуванням, тож саме вам вирішувати, як реалізувати їх у спосіб, що має сенс для того, чого ви намагаєтеся досягти.

Прикладом трейту, який не можна вивести, є Display, який відповідає за форматування для кінцевих користувачів. Ви завжди повинні розглядати відповідний спосіб відображення типу для кінцевого користувача. Які частини типу кінцевому користувачу слід дозволити бачити? Які частини будуть для нього релевантними? Який формат даних буде для нього найбільш релевантним? Компілятор Rust не має цього розуміння, тож він не може надати для вас відповідну поведінку за замовчуванням.

Перелік трейтів, що можна виводити, наданий у цьому додатку, не є вичерпним: бібліотеки можуть реалізовувати derive для власних трейтів, роблячи перелік трейтів, які ви можете використовувати з derive, справді відкритим. Реалізація derive вимагає використання процедурного макроса, який розглядається в розділі “Custom derive Macros” у розділі 20.

Debug для виведення для програміста

Трейт Debug вмикає форматування для налагодження у форматних рядках, яке ви позначаєте, додаючи :? усередині заповнювачів {}.

Трейт Debug дозволяє вам друкувати екземпляри типу для цілей налагодження, щоб ви та інші програмісти, які використовують ваш тип, могли перевірити екземпляр у певний момент виконання програми.

Трейт Debug потрібен, наприклад, під час використання макроса assert_eq!. Цей макрос друкує значення екземплярів, переданих як аргументи, якщо твердження про рівність не виконується, щоб програмісти могли побачити, чому два екземпляри не були рівними.

PartialEq і Eq для порівнянь на рівність

Трейт PartialEq дозволяє вам порівнювати екземпляри типу, щоб перевірити рівність, і вмикає використання операторів == та !=.

Виведення PartialEq реалізує метод eq. Коли PartialEq виводиться для структур, два екземпляри є рівними лише якщо всі поля є рівними, і екземпляри не є рівними, якщо будь-яке поле не є рівним. Коли виводиться для переліків, кожен варіант є рівним самому собі і не є рівним іншим варіантам.

Трейт PartialEq потрібен, наприклад, для використання макроса assert_eq!, якому потрібно вміти порівнювати два екземпляри типу на рівність.

Трейт Eq не має методів. Його мета — сигналізувати, що для кожного значення анотованого типу значення є рівним самому собі. Трейт Eq можна застосовувати лише до типів, які також реалізують PartialEq, хоча не всі типи, що реалізують PartialEq, можуть реалізувати Eq. Один приклад цього — типи чисел з плаваючою комою: реалізація чисел з плаваючою комою стверджує, що два екземпляри значення not-a-number (NaN) не є рівними один одному.

Прикладом того, коли потрібен Eq, є ключі в HashMap<K, V>, щоб HashMap<K, V> могла визначити, чи є два ключі однаковими.

PartialOrd і Ord для порівнянь порядку

Трейт PartialOrd дозволяє вам порівнювати екземпляри типу для цілей сортування. Тип, який реалізує PartialOrd, можна використовувати з операторами <, >, <= та >=. Ви можете застосовувати трейт PartialOrd лише до типів, які також реалізують PartialEq.

Виведення PartialOrd реалізує метод partial_cmp, який повертає Option<Ordering>, що буде None, коли надані значення не утворюють порядку. Прикладом значення, яке не утворює порядку, хоча більшість значень цього типу можна порівнювати, є значення з плаваючою комою NaN. Виклик partial_cmp з будь-яким числом з плаваючою комою та значенням NaN з плаваючою комою поверне None.

Коли виводиться для структур, PartialOrd порівнює два екземпляри, порівнюючи значення в кожному полі в порядку, в якому поля з’являються у визначенні структури. Коли виводиться для переліків, варіанти переліку, оголошені раніше у визначенні переліку, вважаються меншими за варіанти, перелічені пізніше.

Трейт PartialOrd потрібен, наприклад, для методу gen_range з крейту rand, який генерує випадкове значення в діапазоні, заданому виразом діапазону.

Трейт Ord дозволяє вам знати, що для будь-яких двох значень анотованого типу існуватиме коректний порядок. Трейт Ord реалізує метод cmp, який повертає Ordering, а не Option<Ordering>, тому що коректний порядок завжди буде можливим. Ви можете застосовувати трейт Ord лише до типів, які також реалізують PartialOrd і EqEq вимагає PartialEq). Коли виводиться для структур і переліків, cmp поводиться так само, як і згенерована реалізація для partial_cmp у PartialOrd.

Прикладом того, коли потрібен Ord, є зберігання значень у BTreeSet<T>, структурі даних, яка зберігає дані на основі порядку сортування значень.

Clone і Copy для дублювання значень

Трейт Clone дозволяє вам явно створити глибоку копію значення, і процес дублювання може включати виконання довільного коду та копіювання даних у купі. Дивіться розділ “Variables and Data Interacting with Clone” у розділі 4 для отримання додаткової інформації про Clone.

Виведення Clone реалізує метод clone, який, коли реалізований для всього типу, викликає clone для кожної частини типу. Це означає, що всі поля або значення в типі також мають реалізовувати Clone, щоб вивести Clone.

Прикладом того, коли потрібен Clone, є виклик методу to_vec на зрізі. Зріз не володіє екземплярами типу, які він містить, але вектор, повернений з to_vec, має володіти своїми екземплярами, тому to_vec викликає clone для кожного елемента. Таким чином, тип, що зберігається у зрізі, має реалізовувати Clone.

Трейт Copy дозволяє вам дублювати значення, лише копіюючи біти, збережені на стеку; жоден довільний код не потрібен. Дивіться розділ “Stack-Only Data: Copy” у розділі 4 для отримання додаткової інформації про Copy.

Трейт Copy не визначає жодних методів, щоб запобігти програмістам від перевизначення цих методів і порушення припущення, що жоден довільний код не виконується. Таким чином, усі програмісти можуть припускати, що копіювання значення буде дуже швидким.

Ви можете вивести Copy для будь-якого типу, усі частини якого реалізують Copy. Тип, який реалізує Copy, також має реалізовувати Clone, тому що тип, який реалізує Copy, має тривіальну реалізацію Clone, яка виконує ту саму задачу, що й Copy.

Трейт Copy рідко потрібен; типи, що реалізують Copy, мають доступні оптимізації, тобто вам не потрібно викликати clone, що робить код лаконічнішим.

Усе, що можливо з Copy, ви також можете досягти з Clone, але код може бути повільнішим або мати використовувати clone у деяких місцях.

Hash для відображення значення у значення фіксованого розміру

Трейт Hash дозволяє вам взяти екземпляр типу довільного розміру і відобразити цей екземпляр у значення фіксованого розміру за допомогою хеш-функції. Виведення Hash реалізує метод hash. Згенерована реалізація методу hash поєднує результат виклику hash для кожної з частин типу, тобто всі поля або значення також мають реалізовувати Hash, щоб вивести Hash.

Прикладом того, коли потрібен Hash, є зберігання ключів у HashMap<K, V> для ефективного зберігання даних.

Default для значень за замовчуванням

Трейт Default дозволяє вам створити значення за замовчуванням для типу. Виведення Default реалізує функцію default. Згенерована реалізація функції default викликає функцію default для кожної частини типу, тобто всі поля або значення в типі також мають реалізовувати Default, щоб вивести Default.

Функція Default::default зазвичай використовується в поєднанні з синтаксисом оновлення структури, обговореним у розділі “Creating Instances from Other Instances with Struct Update Syntax” у розділі 5. Ви можете налаштувати кілька полів структури, а потім задати й використати значення за замовчуванням для решти полів, використовуючи ..Default::default().

Трейт Default потрібен, наприклад, коли ви використовуєте метод unwrap_or_default на екземплярах Option<T>. Якщо Option<T> — це None, метод unwrap_or_default поверне результат Default::default для типу T, що зберігається в Option<T>.