В сопоставлении с образцом значение типа String оказывается недоступным после ветки: какой механизм приводит к этому и как взять данные без перемещения?
Сопоставление по значению может переместить данные из переменной в привязку образца. Поэтому исходное значение или его часть становится недоступной после match. Чтобы сохранить владельца, сопоставляйте с заимствованием: передавайте в match ссылку и получайте ссылки в привязках.
В Rust владение должно быть очевидным для компилятора без сборщика мусора и скрытого копирования. Сопоставление с образцом специально подчиняется тем же правилам владения: образец может потребить значение, переместить его части или только прочитать их через заимствование.
Такой подход предотвращает неявное дублирование ресурсов, например буферов String, и позволяет статически определить, кто отвечает за их освобождение.
Рассмотрим перечисление, содержащее строку. Если сопоставлять значение напрямую и связать строку с именем в образце, строка переместится в это имя. После завершения match прежний владелец не может использовать перемещённые данные.
Неверный выбор формы сопоставления приводит к ошибке компиляции при последующем обращении к владельцу. Простое чтение значения не требует передачи владения, поэтому в такой ситуации перемещение обычно нежелательно.
В первом варианте match message образец Message::Text(text) связывает text с принадлежащей ему строкой. Это перемещение поля из message; после этого использовать перемещённую часть через message нельзя.
В примере match &message сопоставляется ссылка на перечисление. Поэтому text имеет тип &String, а message остаётся владельцем. Время жизни этой ссылки ограничено выполнением сопоставления, если она не сохраняется дольше в допустимом виде.
Важно, что само наличие match не означает обязательного перемещения. Действие определяется образцом: привязка по значению может переместить поле, а привязка через ссылку — только заимствовать его. Образец _ не связывает значение с именем и обычно не извлекает его во владение.
Альтернативой является clone, но он создаёт независимую копию данных, расходует память и время. Его следует выбирать, когда действительно нужны два владельца содержимого, а не применять для обхода правил заимствования.
Обработчик получает сообщение и должен определить его тип, вывести текст и затем передать исходное сообщение в журнал. Сопоставление по значению с извлечением String забирает строку из сообщения, поэтому передача исходного сообщения в журнал становится невозможной.
Вариант с clone сохраняет исходный объект, но дублирует строковый буфер. Вариант с передачей &message выполняет только чтение, не копирует содержимое и оставляет владельца доступным.
Практическим решением будет сопоставление по ссылке. Оно минимизирует затраты, сохраняет исходную структуру для дальнейшей обработки и явно показывает намерение: обработчик анализирует сообщение, а не забирает его содержимое.
Нет. Перемещаются только те части, которые образец связывает с именами по значению или явно извлекает. Если образец не забирает конкретное поле, компилятор может сохранить возможность использовать его; правила отслеживаются по отдельным полям и путям доступа.
match?Можно, если исходный владелец переживает возвращаемую ссылку и его время жизни связано с этой ссылкой. Сопоставление через &value само по себе не сокращает жизнь владельца; оно лишь создаёт временное заимствование. Нельзя вернуть ссылку на локального владельца, который будет уничтожен при выходе из функции.
ref?Оба подхода могут дать заимствованную привязку, но сопоставление &value обычно проще для чтения: ссылка создаётся до сопоставления, и образцы описывают заимствованные данные. ref в образце применялся для явного создания ссылки при сопоставлении самого значения, однако современный стиль чаще использует match &value или соответствующие формы заимствования. В обоих случаях ключевой результат один: содержимое не перемещается из владельца.