Slices

Nesta parte do 4Noobs, iremos falar sobre os Slices e para isso iremos utilizar String sim, ainda falando sobre esse tipo zZzzzZZZ, claro não é algo exclusivo de String, é apenas um pedaço de algo literalmente, mas como já falamos sobre este cara, vamos usar ele mesmo. Não eu não estou com preguiça.

Temos o seguinte trecho de código:

fn main() {
    let texto: String = String::from("Rust 4 Noobs");
}

A partir da String acima, eu quero pegar os 4 primeiros caracteres desta String, como faríamos isso? Utilizaríamos um slice, e com isso vamos ver outro modo de representar uma String.

fn main() {
    let texto: String = String::from("Rust 4 Noobs");
    let slice = quatro_primeiros(&texto);
    println!("{}", slice);
}

fn quatro_primeiros(texto: &String) -> &str {
    &texto[0..4]
}

Para criar um slice utilizamos os colchetes, e dentro dos colchetes informamos o valor de e o valor até, deste modo criamos um slice da nossa String. Vamos entrar com outro exemplo agora, vamos achar o primeiro espaço e retornar a primeira palavra, com algumas coisas que já vimos até aqui:

fn main() {
    let texto: String = String::from("Rust 4 Noobs");
    let slice = primeira_palavra(&texto);
    println!("{}", slice);
}

fn primeira_palavra(texto: &String) -> &str {
    let bytes = texto.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' { //b' ' transforma o espaço em um byte
            return &texto[0..i]
        }
    }
    &texto[..] //caso não ache retorna a string inteira como um slice
}

referência "ausente"

Sendo sincero não encontrei um modo melhor de traduzir "dangling reference", mas ela ocorre quando tentamos retornar uma referência de algo que já foi devolvido ao Sistema Operacional. Vamos utilizar o nosso primeiro exemplo para demonstrar, vamos remover a passagem por referência da nossa função, pegar o ownership e tentar devolver o slice

fn main() {
    let texto: String = String::from("Rust 4 Noobs");
    let slice = quatro_primeiros(&texto);
    println!("{}", slice);
}

fn quatro_primeiros(texto: String) -> &str {
    &texto[0..4]
}

Ao tentar compilar o código acima, tentamos devolver um pedaço da String que foi passada como parâmetro, porém quando esta função sai do escopo devolvemos a memória para o Sistema Operacional, então o slice iria apontar para nada, lembra que Rust é memory safe? Então, o compilador não deixa compilar nos devolvendo o seguinte erro

error[E0106]: missing lifetime specifier
 --> main.rs:7:39
  |
7 | fn quatro_primeiros(texto: String) -> &str {
  |                                       ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
help: consider using the `'static` lifetime
  |
7 | fn quatro_primeiros(texto: String) -> &'static str {
  |                                       ~~~~~~~~

error: aborting due to previous error