В сценарии с Cow<'a, str> почему значение не может пережить исходную строку в borrowed-варианте, но может после into_owned?
В borrowed-варианте Cow<'a, str> хранит ссылку с временем жизни 'a, поэтому само значение не может использоваться после уничтожения исходной строки. Метод into_owned при необходимости создаёт собственный String; после этого результат больше не содержит заимствования и может жить независимо от источника.
Cow (Clone on Write) нужен для компромисса между производительностью и владением. Если данные можно вернуть без изменения, используется ссылка без копирования; если требуется независимое или изменяемое значение, данные копируются в принадлежащий тип.
Временная жизнь 'a позволяет выразить эту альтернативу типобезопасно: borrowed-вариант связан с источником, а owned-вариант содержит собственные данные.
Функция может принимать строку от вызывающего кода и в большинстве случаев возвращать её без копирования. Однако иногда результат должен пережить исходную строку или быть изменён независимо от неё.
Если сохранить borrowed-вариант после уничтожения источника, получится висячая ссылка. Если всегда копировать строку заранее, безопасность сохранится, но исчезнет преимущество нулевого копирования.
Cow<'a, str> концептуально имеет два варианта: Borrowed(&'a str) и Owned(String). Аннотация 'a ограничивает только возможность хранения заимствованного содержимого; она не означает, что любой экземпляр Cow фактически содержит ссылку.
into_owned потребляет Cow. Для Borrowed он создаёт принадлежащий String, а для Owned просто возвращает уже имеющийся String без дополнительного копирования. Полученный String не зависит от времени жизни 'a.
Здесь source уничтожается до вывода result, но это безопасно: into_owned скопировал содержимое в String до завершения внутренней области.
Если вместо into_owned сохранить сам Cow в borrowed-варианте, его использование после уничтожения source будет запрещено. Метод to_mut применяет тот же принцип лениво: при необходимости изменения borrowed-вариант сначала клонируется в owned-вариант, после чего возвращается изменяемая ссылка на собственные данные.
Главный компромисс — стоимость копирования. Borrowed-путь экономит память и время, но сохраняет зависимость от источника; owned-путь устраняет зависимость, однако может потребовать выделения памяти и копирования.
Представим парсер конфигурации, который обычно возвращает исходное значение без преобразований, но иногда нормализует его. Всегда возвращать String просто для реализации, однако это создаёт лишние копирования для неизменённых значений.
Возвращать &str дешевле, но такой результат нельзя безопасно поместить в долгоживущий объект или передать за пределы области жизни входных данных. Хранить оба варианта вручную через отдельные типы усложняет API.
Cow<'a, str> выбирает borrowed-путь для неизменённых данных, а при нормализации создаёт owned-путь. Если результат должен гарантированно пережить вход, вызывающий код применяет into_owned; это явно фиксирует момент отказа от заимствования и сохраняет копирование только там, где оно действительно нужно.
Всегда ли into_owned выполняет копирование?
Нет. Копирование требуется, если исходный вариант — Borrowed. Если Cow уже содержит Owned(String), into_owned возвращает этот String, перемещая владение. Поэтому название метода описывает результат, а не обязательную стоимость операции.
Может ли сам Cow пережить источник, если его lifetime-параметр 'a всё ещё указан в типе?
Да, если конкретный экземпляр находится в owned-варианте. Параметр 'a описывает допустимую заимствованную форму типа, но не доказывает, что каждый экземпляр содержит ссылку. При этом компилятор всё равно проверит, что borrowed-вариант не используется после завершения 'a.
Почему to_mut безопасен, если он возвращает изменяемую ссылку?
Перед выдачей изменяемой ссылки to_mut проверяет вариант. Для borrowed-варианта он создаёт owned-копию, поэтому изменение не затрагивает исходные данные и не требует продлевать их время жизни. Для owned-варианта изменяется уже принадлежащий String.