惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
Stack Overflow Blog
Stack Overflow Blog
L
LINUX DO - 最新话题
Google Online Security Blog
Google Online Security Blog
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
www.infosecurity-magazine.com
www.infosecurity-magazine.com
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
V
Vulnerabilities – Threatpost
K
Kaspersky official blog
S
Schneier on Security
B
Blog
The Register - Security
The Register - Security
SecWiki News
SecWiki News
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security Affairs
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
T
Tenable Blog
P
Proofpoint News Feed
Apple Machine Learning Research
Apple Machine Learning Research
D
DataBreaches.Net
S
Secure Thoughts
Security Latest
Security Latest
H
Heimdal Security Blog
The Hacker News
The Hacker News
O
OpenAI News
AWS News Blog
AWS News Blog
量子位
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
腾讯CDC
U
Unit 42
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com
NISL@THU
NISL@THU
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hugging Face - Blog
Hugging Face - Blog
The Last Watchdog
The Last Watchdog
Recorded Future
Recorded Future
V2EX - 技术
V2EX - 技术
爱范儿
爱范儿
F
Full Disclosure

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Вы неправильно используете clone() в Rust
badcasedaily · 2026-05-01 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение5 мин

Охват и читатели360

Туториал

Материал подготовлен в рамках курса «Rust-разработчик. Продвинутый уровень».

Когда borrow checker не пропускает код, самое простое решение: добавить .clone(). Компилятор доволен, код работает. Но вот незадача, что clone() в таком сценарии не решает проблему, а прячет её. Borrow checker сказал, что с владением что‑то не так, а вы вместо исправления просто скопировали данные.

Через полгода в проекте десятки clone(), каждый из которых аллоцирует, и профилировщик показывает, что заметная часть времени уходит на копирование строк.

Clone чтобы угодить borrow checker

fn process(data: &mut Vec<String>) {
    for item in data.clone() {  // clone всего вектора!
        if item.starts_with("error") {
            data.push(format!("found: {}", item));
        }
    }
}

Borrow checker не даёт итерироваться по data и одновременно его мутировать. Разработчик клонирует весь вектор. Если в data тысяча строк, это тысяча аллокаций на пустом месте.

Решение простое: собрать результат отдельно и добавить после цикла.

fn process(data: &mut Vec<String>) {
    let new_items: Vec<String> = data.iter()
        .filter(|item| item.starts_with("error"))
        .map(|item| format!("found: {}", item))
        .collect();
    data.extend(new_items);
}

Одна аллокация на новый вектор вместо копирования всего старого.

String вместо &str в сигнатуре

fn connect(url: String) { /* ... */ }

fn main() {
    let config = load_config();
    connect(config.db_url.clone());  // clone, потому что config нужен дальше
    println!("key: {}", config.api_key);
}

Функция connect принимает String по значению, хотя внутри, скорее всего, только читает URL. Clone появляется из‑за того, что API требует владения, хотя ему достаточно ссылки.

fn connect(url: &str) { /* ... */ }

fn main() {
    let config = load_config();
    connect(&config.db_url);  // без clone
    println!("key: {}", config.api_key);
}

Если функция не сохраняет значение и не передаёт его дальше во владение, она должна принимать ссылку. Для строк это почти всегда &str вместо String.

Clone в замыканиях

let name = String::from("Alice");

let make_message = move || {
    format!("Hello, {}!", name)
};

// println!("{}", name);  // ошибка: name moved в замыкание

Часто замыкание только читает данные, и ему достаточно ссылки:

let name = String::from("Alice");

let make_message = || {
    format!("Hello, {}!", &name)  // захват по ссылке
};

println!("{}", make_message());
println!("{}", name);  // работает

Clone в замыканиях реально нужен в двух случаях: когда замыкание уходит в другой поток (требуется move + Send) и когда замыкание переживает данные, на которые ссылается. Во всех остальных случаях стоит попробовать ссылку.

Clone из‑за HashMap

let mut map: HashMap<String, Vec<i32>> = HashMap::new();
let key = String::from("scores");

map.entry(key.clone()).or_insert_with(Vec::new).push(42);
// clone потому что entry забирает key, а он нужен дальше

Entry API забирает ключ по значению, потому что может вставить его в map. Если ключ уже есть, владение пропадёт зря.

Решение: проверить наличие отдельно и аллоцировать только при вставке.

fn get_or_create(
    map: &mut HashMap<String, Vec<i32>>,
    key: &str,
) -> &mut Vec<i32> {
    if !map.contains_key(key) {
        map.insert(key.to_owned(), Vec::new());
    }
    map.get_mut(key).unwrap()
}

Аллокация только при вставке нового ключа. Для существующих ключей ноль аллокаций.

Arc вместо clone

Когда одни и те же данные нужны нескольким потокам, clone копирует всё содержимое. На большой структуре (конфигурация, кеш, справочник) это дорого.

let config = load_config();

let handle1 = thread::spawn({
    let config = config.clone();  // полная копия
    move || use_config(&config)
});

Если потоки только читают данные, Arc решает задачу без копирования:

let config = Arc::new(load_config());

let handle1 = thread::spawn({
    let config = Arc::clone(&config);  // инкремент счётчика, не копия
    move || use_config(&config)
});

Arc::clone увеличивает атомарный счётчик ссылок, это одна атомарная операция вместо глубокого копирования. Данные существуют в одном экземпляре.

Для однопоточного кода Arc не нужен, есть Rc (без атомарных операций, дешевле). Если данные нужно мутировать из нескольких мест, Rc<RefCell<T>> или Arc<Mutex<T>> дают shared ownership с внутренней мутабельностью. Это сложнее, чем просто clone(), но зато вы не копируете данные на каждый чих:

use std::rc::Rc;
use std::cell::RefCell;

let shared_state = Rc::new(RefCell::new(Vec::new()));

let state_for_callback = Rc::clone(&shared_state);
let callback = move || {
    state_for_callback.borrow_mut().push(42);
};

callback();
println!("{:?}", shared_state.borrow());  // [42]

Как найти лишние clone() в проекте

Clippy ловит часть случаев. cargo clippy выдаёт предупреждения вроде redundant_clone (clone() на значении, которое больше не используется) и clone_on_copy (clone() на Copy‑типе, где достаточно копирования). Но Clippy не ловит архитектурные clone(), где копирование формально корректно, но не нужно.

Для тех случаев помогает grep:

grep -rn "\.clone()" src/ | wc -l

Если в проекте на 10К строк больше 50 вызовов clone(), стоит пройтись по ним и спросить себя по каждому: зачем здесь копия? Если ответ «чтобы компилятор замолчал», это кандидат на рефакторинг.

Ещё один приём: временно заменить clone() на todo!() и посмотреть, где компилятор ругается. Те места, где после замены ошибка говорит «value moved here», показывают реальные конфликты владения, которые clone() прятал:

// вместо
let data = original.clone();
// временно поставьте
let data = todo!("why clone?");

Проект не скомпилируется, зато вы увидите, почему borrow checker требовал копию в каждом конкретном месте.

Когда clone нормален

Не каждый clone — это ошибка.

Маленькие Copy‑типы (i32, f64, bool) клонируются бесплатно. Маленькие строки и вектора на несколько элементов стоят наносекунды, и усложнять архитектуру ради этого бессмысленно. При прототипировании clone позволяет быстро проверить идею и вернуться к оптимизации позже.

Проблема не в clone как таковом, а в clone как затычке для borrow checker. Каждый раз, когда вы добавляете clone, чтобы компилятор замолчал, стоит остановиться и спросить: «Я копирую данные, потому что мне нужна копия, или потому что не разобрался с владением?» Если второе, компилятор подсказывает вам, что архитектура требует внимания, а clone прячет эту подсказку.

Если хочется разобраться с Rust не на уровне «компилятор снова недоволен», а через реальные инженерные задачи, обратите внимание на курс «Rust‑разработчик. Продвинутый уровень». Он подойдёт тем, кто уже знаком с языком и хочет увереннее работать с владением, асинхронностью, многопоточностью, сетевым взаимодействием и подходами к промышленной разработке.

📌 Перед стартом можно пройти бесплатное вступительное тестирование — оно поможет оценить текущий уровень и понять, насколько программа подходит под ваши задачи.

А ещё в рамках курса проходят бесплатные открытые уроки от преподавателей‑практиков: на них можно познакомиться с экспертами, протестировать формат обучения и задать вопросы.

Ближайшие открытые уроки:

6 мая в 20:00 «Rust в деле: пишем многопользовательский чат с сервером, клиентом и CLI».
Разберём end‑to‑end проект: от сетевого протокола до работающего чата с сервером, клиентом и CLI.

19 мая в 20:00 — «Асинхронность под капотом».
Поговорим о том, как Rust представляет асинхронные задачи, что делает компилятор с async fn и почему понимание этих деталей помогает писать более предсказуемый код.