Skip to content

Commit f34e6ff

Browse files
committed
Copy in some documentation about which casts are legal
1 parent bac2b13 commit f34e6ff

File tree

1 file changed

+59
-5
lines changed

1 file changed

+59
-5
lines changed

src/doc/book/casting-between-types.md

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,71 @@ most dangerous features of Rust!
77

88
# `as`
99

10-
The `as` keyword does basic casting:
10+
The `as` keyword does safe casting:
1111

1212
```rust
1313
let x: i32 = 5;
1414

1515
let y = x as i64;
1616
```
1717

18-
It only allows certain kinds of casting, however:
18+
There are three major categories of safe cast: explicit coercions, casts
19+
between numeric types, and pointer casts.
20+
21+
Casting is not transitive: even if `e as U1 as U2` is a valid
22+
expression, `e as U2` is not necessarily so (in fact it will only be valid if
23+
`U1` coerces to `U2`).
24+
25+
26+
## Explicit coercions
27+
28+
A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
29+
30+
For example:
31+
32+
```rust
33+
let a = "hello";
34+
let b = a as String
35+
```
36+
37+
Coercions always occur implicitly so this form is only for clarity.
38+
39+
## Numeric casts
40+
41+
A cast `e as U` is also valid in any of the following cases:
42+
43+
* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
44+
* `e` is a C-like enum and `U` is an integer type; *enum-cast*
45+
* `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
46+
* `e` has type `u8` and `U` is `char`; *u8-char-cast*
47+
48+
For example
49+
50+
```rust
51+
let one = true as u8;
52+
let at_sign = 64 as char;
53+
```
54+
55+
## Pointer casts
56+
57+
Perhaps surprisingly, it is safe to cast pointers to and from integers, and
58+
to cast between pointers to different types subject to some constraints. It
59+
is only unsafe to dereference the pointer.
60+
61+
* `e` has type `*T`, `U` is a pointer to `*U_0`, and either `U_0: Sized` or
62+
unsize_kind(`T`) = unsize_kind(`U_0`); a *ptr-ptr-cast*
63+
* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
64+
* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
65+
* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
66+
* `e` is a function pointer type and `U` has type `*T`,
67+
while `T: Sized`; *fptr-ptr-cast*
68+
* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
69+
70+
71+
# `transmute`
72+
73+
`as` only allows safe casting, and will for example reject an attempt to
74+
cast four bytes into a `u32`:
1975

2076
```rust,ignore
2177
let a = [0u8, 0u8, 0u8, 0u8];
@@ -31,13 +87,11 @@ let b = a as u32; // four eights makes 32
3187
^~~~~~~~
3288
```
3389

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

39-
# `transmute`
40-
4195
The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
4296
what it does is very simple, but very scary. It tells Rust to treat a value of
4397
one type as though it were another type. It does this regardless of the

0 commit comments

Comments
 (0)