Type safety keeps values from being used in operations their types do not support. Rust favors compile-time checks: the compiler rejects an invalid operation before the program runs. Types also give meaning to data; the same bit pattern can represent different numbers when interpreted as signed or unsigned. section 1.6.3 section 5.1
Comparing two integer types
Suppose a is an i32 containing 10 and b is a u16 containing 100. Rust rejects a < b because the operands have different types. Writing a < (b as i32) makes the conversion explicit. Casting a smaller integer type to a larger one is generally safer than converting in the other direction: 300_i32 as i8 produces 44. section 2.3.3
When a conversion might fail, try_into() offers an alternative to as. It returns a Result rather than simply treating every conversion as successful. Comparison operators themselves are supported through traits; understanding their full machinery is not necessary to use these examples. section 2.3.3
Listing 2.5 The try_into() method converts between types
use std::convert::TryInto; #1
fn main() {
let a: i32 = 10;
let b: u16 = 100;
let b_ = b.try_into()
.unwrap(); #2
if a < b_ {
println!("Ten is less than one hundred.");
}
}
Compare the explicit try_into() conversion with the earlier rejected comparison: both operands have the same type by the time < is evaluated. section 2.3.3
A type can also express what a value represents. Replacing bare satellite ID integers with a CubeSat struct makes that distinction explicit, but changes how the program handles the values. Passing a CubeSat to a function moves its ownership; using the same value again then fails to compile unless that ownership issue is addressed. section 4.1.1
Type safety has a deliberate escape hatch. std::mem::transmute() can reinterpret a value’s bits as another type inside an unsafe block, but it discards type-safety guarantees. Investigate alternatives first: unsafe makes the programmer responsible for maintaining the program’s integrity. section 5.1







