Хотя общее правило точно такое же, как и в этом ответе В чем различия между `String` и` str` в Rust? , я отвечу и здесь.
Ссылка на Rust - это (почти) именно то, что вы описали: указатель на значение где-то в памяти. (Это не всегда. Например, срезы также содержат длину, а указатели на черты также содержат v-таблицу. Они называются жирными указателями). В начале, Box<T>
- это значение, как и любое другое значение в Rust, поэтому разница очевидна - один - это ссылка на место в памяти, а второй - это значение где-то в памяти. Путаница заключается в том, что Box<T>
внутренне содержит ссылку на память, но эта ссылка размещается в куче, а не в стеке. Разница между этими двумя заключается в том, что стек является локальным для функции и довольно небольшим (на моем macOS это максимум 8192 КиБ).
Например, вы не можете сделать что-то подобное по нескольким причинам:
fn foo() -> &u32 {
let a = 5;
&a
}
Самая важная причина в том, что a
не будет там после возвращения foo()
. Эта память будет стерта (но не всегда), и, возможно, она скоро будет изменена на другое значение. Это неопределенное поведение в C и C ++ и ошибка в Rust, которая не допускает никакого неопределенного поведения (в коде, который не использует unsafe
).
С другой стороны, если вы выполните:
fn foo() -> Box<u32> {
let a = Box::new(5);
a
}
Произойдет несколько важных для нас вещей:
- будет выделена память в стеке. Эта память полностью независима от текущей области действия функции, что означает, что она должна быть освобождена, когда она не понадобится
- , мы переместим значение , поэтому время жизни не требуется
- владение
a
будет передано вызывающей стороне
Для удобства Box<T>
будет вести себя как ссылка во многих случаях, так как эти два часто могут использоваться взаимозаменяемо. Например, посмотрите эту программу C, в которой мы предоставляем функциональность, аналогичную второму примеру:
int* foo(void) {
int* a = malloc(sizeof(int));
*a = 5;
return a;
}
Как вы можете видеть, указатель используется для хранения адреса памяти, и он передается дальше.