Перейти к содержимому

Ошибка Rust E0614: type cannot be dereferenced (лишняя звёздочка *)

E0614 значит: ты поставил * перед тем, что не является ссылкой, поэтому переходить некуда. Оператор * значит «перейди к значению, на которое указывает эта ссылка». А обычный u32, i32 или структура никуда не указывает: это и есть значение. Обычно так бывает в замыканиях и циклах, где легко запутаться, что у тебя — &u32 или u32. rustc называет настоящий тип прямо в заголовке, а исправление почти всегда — удалить одну *. (Эта страница входит в раздел Ошибки компилятора Rust с объяснениями.)

error[E0614]: type `u32` cannot be dereferenced
--> src/main.rs:3:64
|
3 | let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` is already a `u32`
| ^^^^^^ can't be dereferenced

По-русски: «тип u32 нельзя разыменовать». То есть к значению u32 нельзя применить *.

Вот программа, которая её вызывает (комментарий // ❌ оставлен на английском, потому что rustc цитирует эту строку; он значит «count уже u32»):

fn main() {
let visits: Vec<u32> = vec![12, 0, 7, 30];
let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` is already a `u32`
println!("{:?}", doubled);
}

^^^^^^ указывает на *count в строке 3 с пометкой «can’t be dereferenced» («нельзя разыменовать»). Заголовок говорит, чем count является на самом деле: u32, а не &u32.

Пройди по цепочке и проследи типы:

  1. visits.iter() даёт ссылки на элементы: &u32, &u32, …
  2. .copied() превращает каждую &u32 в обычную копию u32. Ссылок больше нет.
  3. Поэтому в .map(|count| ...) count — это u32, а *count просит Rust перейти по указателю, которого не существует.

Когда в заголовке написано type `{integer}` cannot be dereferenced, это то же самое. {integer} — так rustc записывает «какой-то целочисленный тип, который я ещё не определил»; обычно это число вроде 72, которому ты не указал тип.

Это как спросить у человека «что лежит по этому адресу?» и вручить ему саму посылку вместо бумажки с адресом. Вещь уже у него в руках — идти некуда.

В Rust ссылка (&T) и само значение (T) — разные типы. * работает только с тем, что куда-то указывает: со ссылками &T и &mut T, умными указателями вроде Box<T> и Rc<T> и любым типом, который реализует трейт Deref. У u32 или обычной структуры ничего такого нет, поэтому * к ним не имеет смысла.

Rust мог бы тихо проигнорировать лишнюю *, но не делает этого. Лишняя * обычно значит, что ты ошибаешься насчёт своего типа, а такая путаница часто ведёт к другим багам: сравниваются не те вещи или перемещается значение, которое ты хотел заимствовать. Поэтому rustc останавливается и называет настоящий тип. Подробнее — в уроках Заимствование и Умные указатели.

У обратной ошибки свой код. Если ты забыл * у ссылки, например count > 10, где count — &u32, получишь E0308, несовпадение типов.

Это нужно почти всегда, особенно после .copied(), .cloned(), .into_iter() у Vec или чего-то ещё, что отдаёт значения. Значение уже у тебя, просто используй его:

fn main() {
let visits: Vec<u32> = vec![12, 0, 7, 30];
let doubled: Vec<u32> = visits.iter().copied().map(|count| count * 2).collect();
println!("{:?}", doubled);
// `filter` одалживает замыканию каждый элемент, поэтому здесь `count` — это `&u32`,
// и `*` стоит правильно.
let busy: Vec<u32> = visits.iter().copied().filter(|count| *count > 10).collect();
println!("{:?}", busy);
}

Вывод:

[24, 0, 14, 60]
[12, 30]
▶ Попробуй сам

На второй части спотыкаются многие: в одной и той же цепочке map получает сам элемент, а filter — ссылку на элемент. Если сомневаешься, посмотри метод в документации. filter принимает FnMut(&Self::Item) -> bool, с &. Подробнее — в уроках Итераторы и Замыкания.

Исправление 2: В цикле for выбери значения или ссылки

Заголовок раздела «Исправление 2: В цикле for выбери значения или ссылки»

Выбирай этот вариант, когда * стоит внутри цикла for. for score in scores разбирает Vec и отдаёт каждое значение, поэтому *score не работает:

error[E0614]: type `{integer}` cannot be dereferenced
--> src/main.rs:5:18
|
5 | total += *score; // ❌ `score` is a number, not a reference
| ^^^^^^ can't be dereferenced

Программа с ошибкой (комментарий значит «score — число, а не ссылка»):

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in scores {
total += *score; // ❌ `score` is a number, not a reference
}
println!("total: {}", total);
}

Либо убери *, либо перебирай &scores. Тогда каждый score — это &i32, * стоит правильно, и Vec можно использовать после цикла:

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in &scores {
total += *score; // теперь `score` — это `&i32`
}
println!("итого: {}", total);
// `scores` не переместился в цикл, поэтому он всё ещё здесь.
println!("оценок: {}, в среднем {}", scores.len(), total / scores.len() as i32);
}

Вывод:

итого: 255
оценок: 3, в среднем 85
▶ Попробуй сам

Простое правило: for x in v даёт значения, for x in &v — ссылки &, for x in &mut v — ссылки &mut. * нужна только в двух последних случаях. Подробнее — в уроках Циклы for и Векторы.

Исправление 3: Разбери ссылку через &x или используй *x, но не то и другое сразу

Заголовок раздела «Исправление 3: Разбери ссылку через &x или используй *x, но не то и другое сразу»

Выбирай этот вариант, когда в образце замыкания или цикла уже есть &, например |&p|. & в образце сам распаковывает ссылку, так что p — обычное число, а *p — уже лишний шаг:

error[E0614]: type `{integer}` cannot be dereferenced
--> src/main.rs:3:53
|
3 | let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` already removed the `&`
| ^^ can't be dereferenced

Программа с ошибкой (комментарий значит «&p уже убрал &»):

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` already removed the `&`
println!("{:?}", with_fee);
}

Выбери один способ избавиться от ссылки. Обе строки ниже делают одно и то же:

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| p + 1).collect(); // образец убирает `&`
let same: Vec<i32> = prices.iter().map(|p| *p + 1).collect(); // `*` убирает `&`
println!("{:?} {:?}", with_fee, same);
// `filter` после `.iter()` получает `&&i32`: два `&`, поэтому образец — `&&p`.
let pricey = prices.iter().filter(|&&p| p > 4).count();
println!("дорогих товаров: {}", pricey);
}

Вывод:

[4, 6, 9] [4, 6, 9]
дорогих товаров: 2
▶ Попробуй сам

С циклами то же самое: for &(name, qty) in &orders распаковывает каждую ссылку, так что name и qty используй без *. Подробнее — в уроке Сопоставление с образцом.

Исправление 4: Проверь тип и для обёрток используй поле или Deref

Заголовок раздела «Исправление 4: Проверь тип и для обёрток используй поле или Deref»

Выбирай этот вариант, когда заголовок называет твой собственный тип, например type `Meters` cannot be dereferenced. Структура — тоже не ссылка, даже если она оборачивает всего одно значение:

error[E0614]: type `Meters` cannot be dereferenced
--> src/main.rs:5:18
|
5 | let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference
| ^^^^ can't be dereferenced

Программа с ошибкой (комментарий значит «run — это Meters, а не ссылка»):

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference
println!("{} m", longer);
}

Чтобы достать число из кортежной структуры, используй её поле .0:

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = run.0 + 1.0;
println!("{} м", longer);
}

Вывод:

3.5 м
▶ Попробуй сам

Если твой тип действительно обёртка вроде умного указателя и ты хочешь, чтобы * работала, реализуй для него std::ops::Deref. Делай так только для типов-обёрток; для «нового типа» (newtype) вроде Meters понятнее .0 или метод. Не уверен, какой тип у переменной? Наведи на неё курсор в редакторе (rust-analyzer покажет тип) или доверься заголовку: он всегда называет настоящий тип. Подробнее — в уроках Структуры и Умные указатели.

* перед полем структуры. *config.retries, где config — структура (или ссылка на неё), а retries — u32, даёт type `u32` cannot be dereferenced. Точка . уже сама проходит по ссылке. Исправление: config.retries.

Перебор HashMap по значению. for (word, count) in counts { total += *count; } даёт type `u32` cannot be dereferenced, потому что перебор самого counts отдаёт ключи и значения во владение. Исправление: убери * или перебирай &counts, если хеш-таблица нужна и после цикла. Подробнее — в уроке HashMap.

После .copied().max() или .cloned().find(...). Они дают Option<u32>, а не Option<&u32>, поэтому в if let Some(best) = ... { *best } * лишняя. Исправление: используй best напрямую. Без .copied() .iter().max() даёт Option<&u32>, и тогда *best правильно.

  • E0308: несовпадение типов; обратная ошибка — * не хватает там, где ссылка встречается с обычным значением.
  • E0369: бинарную операцию нельзя применить к типу — ещё одна ошибка, когда ссылки и значения перемешиваются.
  • E0507: нельзя переместить значение из-под ссылки; здесь * работает, но переместила бы значение, которое не Copy.
  • E0610: {integer} — примитивный тип без полей, «это просто число»-родственник этой ошибки.
  • E0599: метод не найден, когда значение не того типа, о котором ты думал.
  • Все ошибки компилятора: полный список страниц об ошибках.

Проверь себя

1. Почему в visits.iter().copied().map(|count| *count + 1) выражение *count даёт E0614?

2. for score in &scores { total += *score; }, где scores — Vec<i32>. Скомпилируется?

3. prices.iter().map(|&p| *p * 2) даёт E0614. Какая версия правильная?

Результат: 0 / 3