1. 1. Introduction
  2. 2. Getting Started
  3. 3. Tutorial: Guessing Game
  4. 4. Syntax and Semantics
    1. 4.1. Variable Bindings
    2. 4.2. Functions
    3. 4.3. Primitive Types
    4. 4.4. Comments
    5. 4.5. if
    6. 4.6. Loops
    7. 4.7. Vectors
    8. 4.8. Ownership
    9. 4.9. References and Borrowing
    10. 4.10. Lifetimes
    11. 4.11. Mutability
    12. 4.12. Structs
    13. 4.13. Enums
    14. 4.14. Match
    15. 4.15. Patterns
    16. 4.16. Method Syntax
    17. 4.17. Strings
    18. 4.18. Generics
    19. 4.19. Traits
    20. 4.20. Drop
    21. 4.21. if let
    22. 4.22. Trait Objects
    23. 4.23. Closures
    24. 4.24. Universal Function Call Syntax
    25. 4.25. Crates and Modules
    26. 4.26. `const` and `static`
    27. 4.27. Attributes
    28. 4.28. `type` aliases
    29. 4.29. Casting between types
    30. 4.30. Associated Types
    31. 4.31. Unsized Types
    32. 4.32. Operators and Overloading
    33. 4.33. Deref coercions
    34. 4.34. Macros
    35. 4.35. Raw Pointers
    36. 4.36. `unsafe`
  5. 5. Effective Rust
    1. 5.1. The Stack and the Heap
    2. 5.2. Testing
    3. 5.3. Conditional Compilation
    4. 5.4. Documentation
    5. 5.5. Iterators
    6. 5.6. Concurrency
    7. 5.7. Error Handling
    8. 5.8. Choosing your Guarantees
    9. 5.9. FFI
    10. 5.10. Borrow and AsRef
    11. 5.11. Release Channels
    12. 5.12. Using Rust without the standard library
  6. 6. Nightly Rust
    1. 6.1. Compiler Plugins
    2. 6.2. Inline Assembly
    3. 6.3. No stdlib
    4. 6.4. Intrinsics
    5. 6.5. Lang items
    6. 6.6. Advanced linking
    7. 6.7. Benchmark Tests
    8. 6.8. Box Syntax and Patterns
    9. 6.9. Slice Patterns
    10. 6.10. Associated Constants
    11. 6.11. Custom Allocators
  7. 7. Glossary
  8. 8. Syntax Index
  9. 9. Bibliography

Casting Between Types

Rust, with its focus on safety, provides two different ways of casting different types between each other. The first, as, is for safe casts. In contrast, transmute allows for arbitrary casting, and is one of the most dangerous features of Rust!

Coercion

Coercion between types is implicit and has no syntax of its own, but can be spelled out with as.

Coercion occurs in let, const, and static statements; in function call arguments; in field values in struct initialization; and in a function result.

The most common case of coercion is removing mutability from a reference:

An analogous conversion is to remove mutability from a raw pointer:

References can also be coerced to raw pointers:

Custom coercions may be defined using Deref.

Coercion is transitive.

as

The as keyword does safe casting:

let x: i32 = 5;

let y = x as i64;Run

There are three major categories of safe cast: explicit coercions, casts between numeric types, and pointer casts.

Casting is not transitive: even if e as U1 as U2 is a valid expression, e as U2 is not necessarily so (in fact it will only be valid if U1 coerces to U2).

Explicit coercions

A cast e as U is valid if e has type T and T coerces to U.

Numeric casts

A cast e as U is also valid in any of the following cases:

For example

let one = true as u8;
let at_sign = 64 as char;
let two_hundred = -56i8 as u8;Run

The semantics of numeric casts are:

Pointer casts

Perhaps surprisingly, it is safe to cast raw pointers to and from integers, and to cast between pointers to different types subject to some constraints. It is only unsafe to dereference the pointer:

let a = 300 as *const char; // a pointer to location 300
let b = a as u32;Run

e as U is a valid pointer cast in any of the following cases:

transmute

as only allows safe casting, and will for example reject an attempt to cast four bytes into a u32:

let a = [0u8, 0u8, 0u8, 0u8];

let b = a as u32; // four u8s makes a u32Run

This errors with:

error: non-scalar cast: `[u8; 4]` as `u32`
let b = a as u32; // four u8s makes a u32
        ^~~~~~~~

This is a ‘non-scalar cast’ because we have multiple values here: the four elements of the array. These kinds of casts are very dangerous, because they make assumptions about the way that multiple underlying structures are implemented. For this, we need something more dangerous.

The transmute function is provided by a compiler intrinsic, and what it does is very simple, but very scary. It tells Rust to treat a value of one type as though it were another type. It does this regardless of the typechecking system, and completely trusts you.

In our previous example, we know that an array of four u8s represents a u32 properly, and so we want to do the cast. Using transmute instead of as, Rust lets us:

use std::mem;

fn main() {
    unsafe {
        let a = [0u8, 1u8, 0u8, 0u8];
        let b = mem::transmute::<[u8; 4], u32>(a);
        println!("{}", b); // 256
        // or, more concisely:
        let c: u32 = mem::transmute(a);
        println!("{}", c); // 256
    }
}Run

We have to wrap the operation in an unsafe block for this to compile successfully. Technically, only the mem::transmute call itself needs to be in the block, but it's nice in this case to enclose everything related, so you know where to look. In this case, the details about a are also important, and so they're in the block. You'll see code in either style, sometimes the context is too far away, and wrapping all of the code in unsafe isn't a great idea.

While transmute does very little checking, it will at least make sure that the types are the same size. This errors:

use std::mem;

unsafe {
    let a = [0u8, 0u8, 0u8, 0u8];

    let b = mem::transmute::<[u8; 4], u64>(a);
}Run

with:

error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
(64 bits)

Other than that, you're on your own!