В Rust, как ссылка может быть указателем на указатель на указатель?

сегодняшняя загадка ржавчины из раздела 4.9 языка программирования ржавчины, первое издание. Пример ссылок и заимствований имеет следующий пример:

fn main() {
    fn sum_vec(v: &Vec<i32>) -> i32 {
        return v.iter().fold(0, |a, &b| a + b);
    }

    fn foo(v1: &Vec<i32>) -> i32 {
        sum_vec(v1);
    }

    let v1 = vec![1, 2, 3];

    let answer = foo(&v1);
    println!("{}", answer);
}

это кажется разумным. Он печатает "6", что вы ожидали бы, если бы v of sum_vec является ссылкой на C++; это просто имя для памяти местоположение, вектор v1 мы определили в main().

затем Я заменил тело sum_vec С этого:

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (*v).iter().fold(0, |a, &b| a + b);
}

он составлен и работал, как и ожидалось. Ладно, это не совсем ... безумие. Компилятор пытается сделать мою жизнь проще, я понимаю. Запутанный, что-то, что я должен запомнить как конкретный ТИК языка, но не совсем сумасшедший. Тогда я попробовал:--11-->

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (**v).iter().fold(0, |a, &b| a + b);
}

он все еще работал! Какого черта?

fn sum_vec(v: &Vec<i32>) -> i32 {
    return (***v).iter().fold(0, |a, &b| a + b);
}

type [i32] cannot be dereferenced. Слава богу, хоть что-то разумное. Но я ожидал, что почти две итерации раньше!

ссылки в Rust не являются C++ "имена для другого места в памяти", но что?--23-- > are они? Они также не являются указателями, и правила о них кажутся либо эзотерическими, либо очень специальными. Что происходит так, что ссылка, указатель и указатель на указатель работают одинаково хорошо здесь?

1 ответов


правила не ad-hoc не совсем эзотерика. Проверьте тип v и это различные разыменовывает:

fn sum_vec(v: &Vec<i32>) {
    let () = v;
}

вы получите:

  1. v ->&std::vec::Vec<i32>
  2. *v ->std::vec::Vec<i32>
  3. **v ->[i32]

первое разыменование вы уже поняли. Второе разыменование происходит благодаря Deref черта. Vec<T> разыменовывает к [T].

при выполнении поиска метода, есть прямой набор правил:

  1. если тип имеет метод, используйте его и закройте поиск.
  2. если ссылка на тип имеет метод, используйте его и закройте поиск.
  3. если тип может быть разыменован, сделайте это, затем вернитесь к шагу 1.
  4. иначе поиск завершается неудачно.

ссылки в Rust не являются именами C++ для другое место в памяти,"

они абсолютно являются именами для места в памяти. Фактически, они компилируются до того же указателя C / C++, который вы знаете.