Conversion and Casting

Both Java and Rust are statically-typed at compile time. Hence, after a variable is declared, assigning a value of a different type (unless it's implicitly convertible to the target type) to the variable is prohibited. There are several ways to convert types in Java that have an equivalent in Rust.

Implicit conversions

Implicit conversions exist in Java as well as in Rust (called type coercions). Consider the following example:

int intNumber = 1;
long longNumber = intNumber; // `int` is implicitly converted to `long`

Rust is much more restrictive with respect to which type coercions are allowed:

let int_number: i32 = 1;
let long_number: i64 = int_number; // error: expected `i64`, found `i32`

An example for a valid implicit conversion using subtyping is:

fn bar<'a>() {
    let s: &'static str = "hi";
    let t: &'a str = s;
}

See also:

Explicit conversions

If converting could cause a loss of information, Java requires explicit conversions using a casting expression:

double a = 1.2;
int b = (int) a;

Rust does not provide coercion between primitive types, but instead uses explicit conversion using the as keyword (casting). Casting in Rust will not cause a panic.

let int_number: i32 = 1;
let long_number: i64 = int_number as _;

Custom conversion

In Rust, the standard library contains an abstraction for converting a value into a different type, in form of the From trait and its reciprocal, Into. When implementing From for a type, a default implementation for Into is automatically provided (called blanket implementation in Rust). The following example illustrates two of such type conversions:

fn main() {
    let my_id = MyId("id".into()); // `into()` is implemented automatically due to the `From<&str>` trait implementation for `String`.
    println!("{}", String::from(my_id)); // This uses the `From<MyId>` implementation for `String`.
}

struct MyId(String);

impl From<MyId> for String {
    fn from(MyId(value): MyId) -> Self {
        value
    }
}

See also: