Handling Ownership and Borrowing
Identifying Ownership and Borrowing in Rust
Rust enforces strict ownership rules. When a function in Rust takes ownership of a value (e.g., Box
, Vec
), it means the caller no longer owns that value and cannot use it again unless ownership is returned. Borrowing (&T
or &mut T
) allows temporary access to a value without transferring ownership.
Pre-Modified Rust Function:
Here’s an example of two functions that demonstrate ownership and borrowing in Rust before modification for interoperability with Java:
#![allow(unused)] fn main() { fn take_ownership(v: Vec<i32>) -> Vec<i32> { // Takes ownership of v v } fn borrow(v: &Vec<i32>) -> i32 { // Borrows v temporarily v[0] } }
Explanation:
take_ownership
:
- Transfers ownership of the
Vec
to the function. - The original owner can no longer use
v
unless ownership is explicitly returned.borrow
: - Borrows the
Vec
temporarily to access its first element without transferring ownership. - The caller retains ownership.
Modified Rust Function
#![allow(unused)] fn main() { #[no_mangle] pub extern "C" fn take_ownership(v: *mut Vec<i32>) -> *mut Vec<i32> { // Transfers ownership of the vector v } #[no_mangle] pub extern "C" fn borrow(v: *mut Vec<i32>) -> i32 { unsafe { (*v)[0] } // Borrowing a raw pointer } }
Explanation:
Check Chapter 2.2(Setting Up Rust)
Handling Ownership in Java
When Rust functions take ownership of values or borrow them, Java developers must manage memory explicitly to prevent leaks or invalid references.
What You Need to Do:
- For functions that take ownership: You need to call the appropriate Rust cleanup function (
like
drop orfree
) usingMethodHandle
in Java. is released once the object is no longer needed. - For borrowed references: Manage memory using
Arena
to ensure that memory remains valid for the borrowed duration.
Java Example (Handling Ownership):
// Create a Rust-owned Box and pass ownership MemorySegment rustBox = (MemorySegment)
RustBindings.createBox.invokeExact(10);
// Call Rust function to take ownership of the box
RustBindings.takeOwnership.invokeExact(rustBox);
// Manually free the Box when done
RustBindings.freeBox.invokeExact(rustBox); // Ensures no memory leaks
Explanation:
MemorySegment represents the Rust-allocated memory in Java. Java interacts with this using the Foreign Function & Memory API. When takeOwnership
is called, the Rust function takes ownership of rustBox
. Java then explicitly calls freeBox
to release the memory allocated in Rust and prevent leaks.