Skip to content

Commit

Permalink
TRPL: type aliases and unsized types
Browse files Browse the repository at this point in the history
  • Loading branch information
steveklabnik committed Apr 22, 2015
1 parent 3860240 commit defdc44
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 2 deletions.
75 changes: 74 additions & 1 deletion src/doc/trpl/type-aliases.md
@@ -1,3 +1,76 @@
% `type` Aliases

Coming soon
The `type` keyword lets you declare an alias of another type:

```rust
type Name = String;
```

You can then use this type as if it were a real type:

```rust
type Name = String;

let x: Name = "Hello".to_string();
```

Note, however, that this is an _alias_, not a new type entirely. In other
words, because Rust is strongly typed, you’d expect a comparison between two
different types to fail:

```rust,ignore
let x: i32 = 5;
let y: i64 = 5;
if x == y {
// ...
}
```

this gives

```text
error: mismatched types:
expected `i32`,
found `i64`
(expected i32,
found i64) [E0308]
if x == y {
^
```

But, if we had an alias:

```rust
type Num = i32;

let x: i32 = 5;
let y: Num = 5;

if x == y {
// ...
}
```

This compiles without error. Values of a `Num` type are the same as a value of
type `i32`, in every way.

You can also use type aliases with generics:

```rust
use std::result;

enum ConcreteError {
Foo,
Bar,
}

type Result<T> = result::Result<T, ConcreteError>;
```

This creates a specialized version of the `Result` type, which always has a
`ConcreteError` for the `E` part of `Result<T, E>`. This is commonly used
in the standard library to create custom errors for each subsection. For
example, [io::Result][ioresult].

[ioresult]: ../std/io/type.Result.html
57 changes: 56 additions & 1 deletion src/doc/trpl/unsized-types.md
@@ -1,3 +1,58 @@
% Unsized Types

Coming Soon!
Most types have a particular size, in bytes, that is knowable at compile time.
For example, an `i32` is thirty-two bits big, or four bytes. However, there are
some types which are useful to express, but do not have a defined size. These are
called ‘unsized’ or ‘dynamically sized’ types. One example is `[T]`. This type
represents a certain number of `T` in sequence. But we don’t know how many
there are, so the size is not known.

Rust understands a few of these types, but they have some restrictions. There
are three:

1. We can only manipulate an instance of an unsized type via a pointer. An
`&[T]` works just fine, but a `[T]` does not.
2. Variables and arguments cannot have dynamically sized types.
3. Only the last field in a `struct` may have a dynamically sized type; the
other fields must not. Enum variants must not have dynamically sized types as
data.

So why bother? Well, because `[T]` can only be used behind a pointer, if we
didn’t have language support for unsized types, it would be impossible to write
this:

```rust,ignore
impl Foo for str {
```

or

```rust,ignore
impl<T> Foo for [T] {
```

Instead, you would have to write:

```rust,ignore
impl Foo for &str {
```

Meaning, this implementation would only work for [references][ref], and not
other types of pointers. With this `impl`, all pointers, including (at some
point, there are some bugs to fix first) user-defined custom smart pointers,
can use this `impl`.

# ?Sized

If you want to write a function that accepts a dynamically sized type, you
can use the special bound, `?Sized`:

```rust
struct Foo<T: ?Sized> {
f: T,
}
```

This `?`, read as “T may be `Sized`”, means that this bound is special: it
lets us match more kinds, not less. It’s almost like every `T` implicitly has
`T: Sized`, and the `?` undoes this default.

0 comments on commit defdc44

Please sign in to comment.