Empréstimo (Borrowing)
Em vez de transferir a ownership ao chamar uma função, você pode permitir que uma função empreste o valor:
#[derive(Debug)] struct Ponto(i32, i32); fn somar(p1: &Ponto, p2: &Ponto) -> Ponto { Ponto(p1.0 + p2.0, p1.1 + p2.1) } fn main() { let p1 = Ponto(3, 4); let p2 = Ponto(10, 20); let p3 = somar(&p1, &p2); println!("{p1:?} + {p2:?} = {p3:?}"); }
- A função
somar
pega emprestado (borrows) dois pontos e retorna um novo ponto. - O chamador mantém a ownership das entradas.
Notas sobre os retornos da pilha:
-
Demonstre que o retorno de
somar
é barato porque o compilador pode eliminar a operação de cópia. Modifique o código acima para imprimir endereços da pilha e execute-o no Playground ou veja o código assembly em Godbolt. No nível de otimização “DEBUG”, os endereços devem mudar, enquanto eles permanecem os mesmos quando a configuração é alterada para “RELEASE”:#[derive(Debug)] struct Ponto(i32, i32); fn somar(p1: &Ponto, p2: &Ponto) -> Ponto { Ponto(p1.0 + p2.0, p1.1 + p2.1) } pub fn main() { let p1 = Ponto(3, 4); let p2 = Ponto(10, 20); let p3 = somar(&p1, &p2); println!("&p3.0: {:p}", &p3.0); println!("{p1:?} + {p2:?} = {p3:?}"); }
-
O compilador Rust pode fazer otimização de valor de retorno (Return Value Operation - RVO).
-
Em C++, a elisão (omissão) de cópia deve ser definida na especificação da linguagem porque os construtores podem ter efeitos colaterais. Em Rust, isso não é um problema. Se o RVO não aconteceu, o Rust sempre executará uma cópia
memcpy
simples e eficiente.