Срез строки против фрагмента и строки - PullRequest
0 голосов
/ 07 августа 2020

Я читал do c с веб-сайта rust lang, и в главе 4 они сделали следующий пример:

let s = String::from("hello world");

let hello = &s[0..5];
let world = &s[6..11];

hello имеет тип &str, который я создал из переменной s типа String.

Некоторые строки ниже определяют следующую функцию:

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

На этот раз s имеет тип &String, но все же &s[0..i] дал мне a &str срез. Как это возможно? Я думал, что правильным способом добиться этого будет что-то вроде &((*str)[0..i]).

Я что-то упускаю? Может быть, во время операции [0..i] Rust автоопределение переменная?

Спасибо

Ответы [ 2 ]

0 голосов
/ 07 августа 2020

Важно понимать, что происходит с &s[1..5], и что это &(s[1..5]), а именно, s[1..5] сначала оценивается, это возвращает значение типа str, и берется ссылка на это значение. Фактически, здесь даже больше косвенности: x[y] в ржавчине на самом деле синтаксис c сахар для *std::ops::Index::index(x,y). Обратите внимание на разыменование, так как эта функция всегда возвращает ссылку, которая затем разыменовывается сахаром, а затем на нее снова ссылается & в нашем коде - естественно, компилятор оптимизирует это и гарантирует, что мы не будем бессмысленно брать ссылки только разыменовать их снова.

Так получилось, что тип String действительно поддерживает черту Index<Range<usize>>, а тип Index::output - str.

Также бывает, что Тип str поддерживает то же самое, и этот тип вывода также str, viā общая реализация SliceIndex.

Что касается вашего вопроса об автоматическом разыменовании, это правда, что в Rust есть черта Deref, определенная в String, так что во многих контекстах, таких как этот, &String автоматически приводится к &str - любой контекст, который принимает &str, также принимает &String, что означает, что реализация на Index<usize> на String на самом деле предназначена для оптимизации, чтобы избежать этого косвенного обращения. Если бы его не было, код все равно работал бы, и, возможно, компилятор мог бы даже оптимизировать косвенное обращение. много разных типов.

Наконец:

Я подумал, что правильным способом добиться этого будет что-то вроде & ((* str) [0..i]).

Это не будет работать независимо, &str не то же самое, что &String, и не может быть разыменован на String как &String. Фактически, &str во многих отношениях ближе к String, чем к &String. a &str на самом деле просто жирный указатель на последовательность байтов Unicode, который также содержит длину указанной последовательности во втором слове; a String - это, если угодно, сверхжирный указатель, который также содержит текущую емкость буфера с ним и владеет буфером, на который он указывает, поэтому он может удалить и изменить его размер.

0 голосов
/ 07 августа 2020

Может быть, во время операции [0..i] Rust автоопределение переменная?

Именно это и происходит. Когда вы вызываете методы / индексируете ссылку, она автоматически разыменовывается перед применением метода. Это поведение также можно реализовать вручную с помощью трейта Deref. String реализует Deref с целью str, что означает, когда вы вызываете str методы на String. Подробнее о приведении deref здесь .

...