Os primeiros meses de um motim novato geralmente chegam a um cabeçalho sobre o conceito de vida e posse. Algumas pessoas falham nisso, mas para aqueles que foram capazes de sobreviver, isso não parece mais incomum ou errado. Descreverei os pontos-chave que, ao que me parece, ajudaram a se adaptar mais rápido e melhor ao conceito de vida e posses. 
Obviamente, o boletim oficial é mais completo e detalhado, mas também requer mais tempo e paciência para entender e absorver completamente todas as informações. Tentei evitar um grande número de detalhes e apresentar tudo em ordem crescente de complexidade, na tentativa de tornar este artigo mais acessível para aqueles que começaram a assistir à série ou que não entendiam realmente os momentos iniciais do quadro de avisos oficial.
Também me fez escrever que, por exemplo, a partir das mônadas, é possível encontrar alguns materiais oficiais de treinamento, mas eles nem sempre são bem compreendidos, e o entendimento surge somente após a leitura de algo como "outra introdução" sobre esse tópico.
Lifetime
Primeiro, precisamos nos acostumar com duas coisas - o final do bloco e mover o valor para outro bloco. Mais tarde, começaremos a complicar adicionando "empréstimos", "mutabilidade" e "mutabilidade oculta".
Primeiro, a vida de um valor é determinada pelo seguinte segmento:
- O começo da vida: criando valor. Isso é comum na maioria das linguagens de programação, portanto, ele não carrega nenhuma carga incomum.
- O fim da vida. É aqui que o Rust chama automaticamente o destruidor e esquece o valor. Em um bloco de escopo, isso acontecerá no final deste bloco sem se mover. É o rastreamento mental do fim da vida que é, na minha opinião, a chave para uma interação bem-sucedida com o tomador de empréstimos.
Vou adicionar um detalhe que pode ser útil: se houver vários valores no escopo, eles serão destruídos na ordem inversa da criação.
Outro ponto: vou criar uma string, porque ela não possui um marcador de cópia, e os valores que possuem esse marcador não se movem, mas são copiados, o que é considerado uma operação bastante barata, mas altera o comportamento da movimentação (e facilita o trabalho com tipos primitivos), mas mais sobre isso mais tarde.
Exemplos podem ser executados aqui: https://play.rust-lang.org/
fn main() { {
Com um bloco simples, tudo é relativamente simples, o próximo estágio ocorre quando usamos coisas aparentemente simples, como funções e fechamentos:
Movendo
Adicione um conceito como mover um valor. Em palavras simples, "mover" significa que o bloco atual não está mais interessado no destino do valor e se esquece dele, e seu destino é transferido para outro bloco, por exemplo, para outra função ou fechamento, ou simplesmente para outro valor.
fn f<T: std::fmt::Display>(x: T) {
Com fechamentos.
Para que o fechamento mova o valor capturado para seu bloco, a palavra-chave move é usada. Se você não escrever move, o valor será emprestado, sobre o qual escreverei muito em breve.
fn main() { let a = "a".to_string();
Você pode mover para a função e da função ou para outro valor.
Este exemplo demonstra como acompanhar as maneiras pelas quais os valores se movem para viver em paz com o emprestador de cheques.
fn f(x: String) -> String { x + " and x"
Empréstimos
Introduzimos este novo conceito: ao contrário de movimento, isso significa que o bloco atual reserva o controle do valor, simplesmente permite que o outro bloco use seu valor.
Observo que o empréstimo também ocorre onde terminou, o que não é muito importante nesses exemplos, mas será exibido no próximo parágrafo.
Nota: Não escreverei sobre como especificar a vida útil diretamente na função, pois a ferrugem moderna faz isso automaticamente melhor do que nos velhos tempos, e a divulgação de tudo isso é mais algumas páginas.
fn f(x: &String) {
Com fechamentos da mesma forma:
fn main() { let mut a = "a".to_string();
Na verdade, na maioria dessas construções simples, o usuário só precisa decidir onde deseja finalizar a vida do valor: no final do bloco atual e emprestando-o a algumas funções, ou, se sabemos que não precisamos mais do valor, mova-o para a função no final pelo qual ela própria será destruída, mais rapidamente liberaremos a memória, mas o valor não estará mais disponível no bloco atual.
Mutabilidade
Em rasta, como, por exemplo, em kotlin, há uma divisão em valores mutáveis e não estáveis. Mas surge o problema de que a mutabilidade afeta os empréstimos:
Você pode emprestar um valor não estável muitas vezes e um valor mutável pode ser emprestado mutuamente apenas uma vez. Você não pode alterar um valor já emprestado anteriormente.
Um exemplo que não está relacionado aos anteriores, quando esse conceito nos salva de problemas ao proibir os empréstimos mutáveis e não estáveis simultâneos:
fn main() { let mut a = "abc".to_string(); for x in a.chars() {
Aqui já é necessário estocar vários truques para satisfazer, na maioria das vezes, as justas reivindicações do rasta. No exemplo acima, o mais fácil seria clonar "a" -> o clone terá um empréstimo não estável e não estará relacionado ao "a" original.
for x in a.clone().chars() {
Mas é melhor voltar aos exemplos para manter a consistência. Precisamos mudar "a" e não podemos fazê-lo.
fn main() { let mut a = "a".to_string();
Mutação oculta
Teoricamente, um fechamento pode ser passado para alguma função que processa, por exemplo, de forma assíncrona em outro encadeamento, e então teríamos realmente problemas, mas, neste caso, o emprestador é ressegurado, embora isso não anule o fato de que precisamos concordar com ele de alguma forma .
Conclusão: precisamos de dois empréstimos mutantes, mas o rast permite apenas uma coisa, mas os inventores astutos do rasta apresentam uma "mutação oculta": RefCell.
RefCell - o que envolvemos no RefCell - a varredura considera não mutável; no entanto, usando a função borrow_mut (), podemos extrair temporariamente um link mutável pelo qual ele pode alterar o valor, mas há uma nuance importante : o link só pode ser obtido quando o RefCell em tempo de execução garante que não haja outros empréstimos ativos; caso contrário, ele entrará em pânico ou retornará um erro se try_borrow_mut () for usado. I.e. aqui o crescimento dá todas as preocupações sobre empréstimos aos cuidados do usuário, e ele próprio deve garantir que não empresta o valor de vários lugares ao mesmo tempo.
use std::cell::RefCell; fn main() { let a = RefCell::new("a".to_string());
Rc Link Counter
Essa construção é familiar em muitos idiomas e é usada em rast, quando, por exemplo, não podemos emprestar um valor por algum motivo, e é necessário ter vários valores de referência para um único valor. Rc, como o nome indica, é simplesmente um contador de referência que possui um valor, pode emprestar links não confiáveis, contar seu número e, assim que seu número é redefinido, destrói o próprio valor. Acontece que Rc permite, por assim dizer, secretamente expandir a vida útil do valor que está contido nela.
Acrescentarei que o rast pode fazer deref automaticamente para as estruturas para as quais está definido, o que significa que, para trabalhar com Rc, como regra, você não precisa de nenhuma extração adicional do valor interno e apenas trabalhamos com Rc como com o valor dentro dele.
Aqui um exemplo simples foi pensado um pouco, vamos tentar emular que o fechamento do exemplo acima não deseja aceitar & T ou & String, mas apenas deseja String:
fn f(x: String) {
Esse problema seria facilmente resolvido se pudéssemos alterar a função para fn f(x: &String)
(ou & str), mas vamos imaginar que, por algum motivo, não possamos usar &
Usamos Rc
use std::rc::Rc; fn f(x: Rc<String>) {
Vou adicionar o último exemplo, já que um dos pares mais frequentes de contêineres que podem ser encontrados é Rc <RefCell>
use std::rc::Rc; use std::cell::RefCell; fn f(x: Rc<RefCell<String>>) { x.borrow_mut().push_str(" and x");
Além disso, seria lógico mover este tutorial para um análogo seguro de thread do Rc-Arc e continuar sobre o Mutex, mas você não falará sobre segurança de thread e verificador de empréstimos em um parágrafo, e não está claro se esse tipo de artigo é necessário, pois existe um thread oficial. Então eu concluo.