Explain transmute

1.Wha is the use of transmute.
2.how it works.
3.when it needed.
4.as vs transmute

For unsafe code in general, you should read the Rustonomicon.

There’s a page about it. Also the documentation of transmute itself does some explaining.

As a beginner or even intermediate Rust programmer you usually don’t really need to use transmute, or any unsafe code. Rust’s memory safety guarantees are easily circumvented when using transmute, i.e. it’s really easy to make mistakes that result in bad program crashes or misbehavior.

The as casting is a totally different story. It is safe to use. All the details about as can be found in the Reference, one of its most common usage is for casting between different numeric types (though you can get unexpected results from truncation on overflows).

So,

it’s an advanced tool that can be used in unsafe Rust code,

it converts between different types by just “reinterpreting the bytes”, kind-of just like “disabling the type-checker” somewhat (if “disabling the type-checker” sounds bad, that’s because it is pretty bad),

It’s needed less often than one might think. One common use is if you have some references/pointers to types that are repr(transparent) struct to convert from the inner type to the struct. Though there are crates that abstract the unsafety away, so it might be preferrable to use those instead if need be. In particular bytemuck offers a lot of abstractions over things that could be archieved with transmute.

I already said some things about as before. One key difference is that as does some intelligent/smart casts. E.g. converting between floating point and integer numbers does try to get the closest numerical value, using as for explicitly coercing to trait objects, e.g. Box<T> to Box<dyn Any> adds the vtable, etc. On the other hand transmute does nothing smart at all. There are a few sanity checks in the compiler, e.g. that the converted types have the same size, but that’s it.

6 Likes

There's another one: it warns if the type you're casting to is uninhabited in the case of zero sized types (ZST).

[Playground]

#![feature(never_type)]

enum Empty {}

fn main() {
    unsafe { std::mem::transmute::<(), !    >(()) };
    unsafe { std::mem::transmute::<(), Empty>(()) };
}

Results in

   Compiling playground v0.0.1 (/playground)

warning: the type `!` does not permit zero-initialization
 --> src/main.rs:6:14
  |
6 |     unsafe { std::mem::transmute::<(), !    >(()) };
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |              |
  |              this code causes undefined behavior when executed
  |              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: `#[warn(invalid_value)]` on by default
  = note: the `!` type has no valid value

warning: the type `Empty` does not permit zero-initialization
 --> src/main.rs:7:14
  |
7 |     unsafe { std::mem::transmute::<(), Empty>(()) };
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |              |
  |              this code causes undefined behavior when executed
  |              help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: enums with no variants have no valid value