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

Copy

Похоже на Clone, но показывает, что тип можно побитово скопировать.

Можно получить через derive: ✅

// Copyright 2025 Google LLC
// SPDX-License-Identifier: Apache-2.0

#[derive(Debug, Clone, Copy)]
pub struct Copyable(u8, u16, u32, u64);

fn main() {
    let copyable = Copyable(1, 2, 3, 4);
    let copy = copyable; // Неявная операция копирования
    dbg!(copyable);
    dbg!(copy);
}
  • Clone — явная, определяемая пользователем операция копирования. Copy — неявное побитовое копирование.

  • Обычно его стоит реализовывать только для типов «простых данных», которые должны вести себя как примитивные значения. Например, примитивные числовые типы для библиотеки линейной алгебры.

  • Здесь то же предостережение, что и для Clone: если дублирование значений нарушит инвариант, тип не должен реализовывать Copy.

  • Всегда получайте Clone и Copy через derive вместе! Не реализуйте Clone вручную, когда реализуете Copy.

    • Операции копирования не вызывают метод clone, поэтому пользовательская реализация Clone может вести себя иначе, чем неявное копирование. Получение обоих трейтов Clone и Copy через derive гарантирует, что вызов clone даст тот же результат, что и копирование.
  • Нельзя реализовать для типов с Drop или с полями, которые не реализуют Copy.

    • Спросите класс: почему тип с данными в куче (Vec, BTreeMap, Rc и т. п.) не может быть Copy?

      Побитовое копирование для этих типов означало бы, что типы с данными в куче больше не обладали бы эксклюзивным владением указателем, что нарушило бы инварианты, которые обычно поддерживают Rust и его экосистема.

      Несколько Vec указывали бы на одни и те же данные в памяти. Добавление и удаление данных обновляли бы значения длины и ёмкости только у отдельных Vec. То же самое для BTreeMap.

      Побитовое копирование Rc не обновило бы значение счётчика ссылок внутри указателей, а значит, могло бы быть два экземпляра Rc, каждый из которых считает себя единственным Rc для этого указателя. Когда один из них уничтожится, счётчик ссылок у него станет 0, и внутреннее значение будет освобождено, хотя другой Rc всё ещё жив.