Borrowing
How to borrow values with references without transferring ownership.
Borrowing
Borrowing allows us to use values without transferring ownership. We use references (&).
References
RUSTlet s1 = String::from("hello"); let s2 = &s1; // s2 is a reference to s1 // s1 is still the owner
Immutable References
RUSTfn calculate_length(s: &String) -> usize { s.len() // we use s, but don't own it } let s = String::from("hello"); let len = calculate_length(&s); println!("{}", s); // s is still usable!
Mutable References
RUSTfn change(s: &mut String) { s.push_str(", world"); } let mut s = String::from("hello"); change(&mut s);
Borrowing Rules
- At any time, you can have either one mutable reference OR any number of immutable references
- References must always be valid
RUSTlet mut s = String::from("hello"); let r1 = &s; // OK let r2 = &s; // OK - multiple immutable references // let r3 = &mut s; // ERROR!
Code Examples
Immutable Reference
Borrowing a value with an immutable reference
fn main() {
let s = String::from("hello");
let len = calculate_length(&s);
println!("The length of '{}' is {} characters.", s, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}Explanation:
The `&s` is a reference to the String. The function can use the value but doesn't own it. The s variable remains usable after the function call.
Mutable Reference
Modifying a value with a mutable reference
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}Explanation:
The `&mut s` is a mutable reference that allows modification of the String. The variable must also be `mut`.
Borrowing Rules
Demonstrating borrowing rules
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{}", r1);
println!("{}", r2);
let r3 = &mut s;
println!("{}", r3);
}Explanation:
At any time, you can have either multiple immutable references OR one mutable reference. The compiler checks these rules.
Blockchain: Validating Without Ownership
Using borrowing for blockchain validation
struct Transaction {
from: String,
to: String,
amount: u64,
fee: u64,
}
fn validate_transaction(tx: &Transaction, sender_balance: u64) -> bool {
tx.amount > 0 &&
tx.fee >= 10 &&
sender_balance >= tx.amount + tx.fee
}
fn main() {
let tx = Transaction {
from: String::from("0xAlice"),
to: String::from("0xBob"),
amount: 100,
fee: 10,
};
let balance = 1000;
if validate_transaction(&tx, balance) {
println!("Transaction is valid");
}
println!("Transaction: {} -> {} ({} tokens)", tx.from, tx.to, tx.amount);
}Explanation:
Borrowing is essential in blockchain for validation. We can check transactions without taking ownership, allowing the transaction to be used elsewhere (e.g., added to a block).
Blockchain: Updating State with Mutable Borrow
Using mutable references to update blockchain state
use std::collections::HashMap;
struct BlockchainState {
balances: HashMap<String, u64>,
}
fn transfer_funds(
state: &mut BlockchainState,
from: &str,
to: &str,
amount: u64
) -> Result<(), String> {
let from_balance = state.balances.get(from).copied().unwrap_or(0);
if from_balance < amount {
return Err(String::from("Insufficient balance"));
}
*state.balances.entry(from.to_string()).or_insert(0) -= amount;
*state.balances.entry(to.to_string()).or_insert(0) += amount;
Ok(())
}
fn main() {
let mut state = BlockchainState {
balances: HashMap::new(),
};
state.balances.insert(String::from("0xAlice"), 1000);
state.balances.insert(String::from("0xBob"), 500);
transfer_funds(&mut state, "0xAlice", "0xBob", 200).unwrap();
println!("Alice: {}", state.balances.get("0xAlice").unwrap());
println!("Bob: {}", state.balances.get("0xBob").unwrap());
}Explanation:
Mutable references allow updating blockchain state (like balances) without taking ownership. This is crucial for state management in blockchain nodes.
Exercises
Using References
Write a function that returns a String's length using a reference!
Starter Code:
fn main() {
let s = String::from("Rust");
let len = get_length();
println!("The length of '{}' is: {}", s, len);
}