Rust Essentials(Second Edition)
上QQ阅读APP看书,第一时间看更新

Type checking and conversions

Rust has to know the type of variables, because that way it can check (at compile time) that they are only used in ways their type permits. That way programs are type safe and a whole range of bugs are avoided.

This also means that we cannot change the type of a variable during its lifetime, because of static typing, for example, the variable score in the following snippet cannot change from an integer to a string:

// see Chapter 2/code/type_errors.rs 
// warning: this code does not work! 
fn main() { 
let score: i32 = 100; 
score = "YOU WON!" 
} 

With this, we get the compiler error, as follows:

error: mismatched types: expected i32, found reference

However, I am allowed to write this as:

let score = "YOU WON!"; 

Rust lets me redefine variables; each let binding creates a new variable score that hides the previous one, which is freed from memory. This is actually quite useful because variables are immutable by default.

Adding strings with + (like the players in the following code) is not defined in Rust:

let player1 = "Rob"; 
let player2 = "Jane"; 
let player3 = player1 + player2; 

With this we get an error stating:

error: binary operation `+` cannot be applied to type `&str`

In Rust you can use the to_string() method to convert the value to a String type like this:

let player3 = player1.to_string() + player2; 

Alternatively, you could use the format! macro:

let player3 = format!("{}{}", player1, player2); 

In both cases, the variable player3 has the value RobJane.

Let's find out what happens when you assign a value from a variable of a certain type to another variable of a different type:

// see Chapter 2/code/type_conversions.rs 
fn main() { 
  let points = 10i32; 
  let mut saved_points: u32 = 0; 
   saved_points = points; // error ! 
} 

This is again not allowed, therefore, we get the same error, as follows:

error: mismatched types: expected u32, found i32

To enable maximal type checking Rust does not permit automatic (or implicit) conversions of one type to another like C++ does, thus avoiding a lot of hard-to-find bugs. For example, the numbers after the decimal point are lost when converting an f32 value to an i32 value; this could lead to errors when done automatically.

We can however do an explicit conversion (also called a casting) with the keyword as follows:

saved_points = points as u32; 

When the variable points contains a negative value, the sign would be lost after conversion. Similarly, when casting from a wider value like a float to an integer, the decimal part is truncated. See the following example:

  let f2 = 3.14; 
  saved_points = f2 as u32; // truncation to value 3 occurs here 

Also, the value must be convertible to the new type, a string cannot be converted to an integer, for example:

  let mag = "Gandalf"; 
   saved_points = mag as u32; // 

This gives an error, as follows:

error: non-scalar cast:`&str`as`u32`