Auto merge of #24703 - Manishearth:rollup, r=Manishearth
r? @Manishearth
This commit is contained in:
commit
90cc83015e
6 changed files with 293 additions and 6 deletions
|
|
@ -9,6 +9,7 @@
|
|||
* [The Stack and the Heap](the-stack-and-the-heap.md)
|
||||
* [Debug and Display](debug-and-display.md)
|
||||
* [Testing](testing.md)
|
||||
* [Conditional Compilation](conditional-compilation.md)
|
||||
* [Documentation](documentation.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Concurrency](concurrency.md)
|
||||
|
|
@ -46,7 +47,6 @@
|
|||
* [`const` and `static`](const-and-static.md)
|
||||
* [Tuple Structs](tuple-structs.md)
|
||||
* [Attributes](attributes.md)
|
||||
* [Conditional Compilation](conditional-compilation.md)
|
||||
* [`type` aliases](type-aliases.md)
|
||||
* [Casting between types](casting-between-types.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,70 @@
|
|||
% Attributes
|
||||
|
||||
Coming Soon!
|
||||
Declarations can be annotated with ‘attributes’ in Rust. They look like this:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
or like this:
|
||||
|
||||
```rust
|
||||
# mod foo {
|
||||
#![test]
|
||||
# }
|
||||
```
|
||||
|
||||
The difference between the two is the `!`, which changes what the attribute
|
||||
applies to:
|
||||
|
||||
```rust,ignore
|
||||
#[foo]
|
||||
struct Foo;
|
||||
|
||||
mod bar {
|
||||
#![bar]
|
||||
}
|
||||
```
|
||||
|
||||
The `#[foo]` attribute applies to the next item, which is the `struct`
|
||||
declaration. The `#![bar]` attribute applies to the item enclosing it, which is
|
||||
the `mod` declaration. Otherwise, they’re the same. Both change the meaning of
|
||||
the item they’re attached to somehow.
|
||||
|
||||
For example, consider a function like this:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn check() {
|
||||
assert_eq!(2, 1 + 1);
|
||||
}
|
||||
```
|
||||
|
||||
It is marked with `#[test]`. This means it’s special: when you run
|
||||
[tests][tests], this function will execute. When you compile as usual, it won’t
|
||||
even be included. This function is now a test function.
|
||||
|
||||
[tests]: testing.html
|
||||
|
||||
Attributes may also have additional data:
|
||||
|
||||
```rust
|
||||
#[inline(always)]
|
||||
fn super_fast_fn() {
|
||||
# }
|
||||
```
|
||||
|
||||
Or even keys and values:
|
||||
|
||||
```rust
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos_only {
|
||||
# }
|
||||
```
|
||||
|
||||
Rust attributes are used for a number of different things. There is a full list
|
||||
of attributes [in the reference][reference]. Currently, you are not allowed to
|
||||
create your own attributes, the Rust compiler defines them.
|
||||
|
||||
[reference]: reference.html#attributes
|
||||
|
|
|
|||
|
|
@ -1,3 +1,93 @@
|
|||
% Conditional Compilation
|
||||
|
||||
Coming Soon!
|
||||
Rust has a special attribute, `#[cfg]`, which allows you to compile code
|
||||
based on a flag passed to the compiler. It has two forms:
|
||||
|
||||
```rust
|
||||
#[cfg(foo)]
|
||||
# fn foo() {}
|
||||
|
||||
#[cfg(bar = "baz")]
|
||||
# fn bar() {}
|
||||
```
|
||||
|
||||
They also have some helpers:
|
||||
|
||||
```rust
|
||||
#[cfg(any(unix, windows))]
|
||||
# fn foo() {}
|
||||
|
||||
#[cfg(all(unix, target_pointer_width = "32"))]
|
||||
# fn bar() {}
|
||||
|
||||
#[cfg(not(foo))]
|
||||
# fn not_foo() {}
|
||||
```
|
||||
|
||||
These can nest arbitrarily:
|
||||
|
||||
```rust
|
||||
#[cfg(any(not(unix), all(target_os="macos", target_arch = "powerpc")))]
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
As for how to enable or disable these switches, if you’re using Cargo,
|
||||
they get set in the [`[features]` section][features] of your `Cargo.toml`:
|
||||
|
||||
[features]: http://doc.crates.io/manifest.html#the-[features]-section
|
||||
|
||||
```toml
|
||||
[features]
|
||||
# no features by default
|
||||
default = []
|
||||
|
||||
# The “secure-password” feature depends on the bcrypt package.
|
||||
secure-password = ["bcrypt"]
|
||||
```
|
||||
|
||||
When you do this, Cargo passes along a flag to `rustc`:
|
||||
|
||||
```text
|
||||
--cfg feature="${feature_name}"
|
||||
```
|
||||
|
||||
The sum of these `cfg` flags will determine which ones get activated, and
|
||||
therefore, which code gets compiled. Let’s take this code:
|
||||
|
||||
```rust
|
||||
#[cfg(feature = "foo")]
|
||||
mod foo {
|
||||
}
|
||||
```
|
||||
|
||||
If we compile it with `cargo build --features "foo"`, it will send the `--cfg
|
||||
feature="foo"` flag to `rustc`, and the output will have the `mod foo` in it.
|
||||
If we compile it with a regular `cargo build`, no extra flags get passed on,
|
||||
and so, no `foo` module will exist.
|
||||
|
||||
# cfg_attr
|
||||
|
||||
You can also set another attribute based on a `cfg` variable with `cfg_attr`:
|
||||
|
||||
```rust
|
||||
#[cfg_attr(a, b)]
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
Will be the same as `#[b]` if `a` is set by `cfg` attribute, and nothing otherwise.
|
||||
|
||||
# cfg!
|
||||
|
||||
The `cfg!` [syntax extension][compilerplugins] lets you use these kinds of flags
|
||||
elsewhere in your code, too:
|
||||
|
||||
```rust
|
||||
if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
|
||||
println!("Think Different!");
|
||||
}
|
||||
```
|
||||
|
||||
[compilerplugins]: compiler-plugins.html
|
||||
|
||||
These will be replaced by a `true` or `false` at compile-time, depending on the
|
||||
configuration settings.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -195,9 +195,11 @@ fn test_write() {
|
|||
write!(w, "{}", "hello");
|
||||
writeln!(w, "{}", "line");
|
||||
writeln!(w, "{foo}", foo="bar");
|
||||
w.write_char('☃');
|
||||
w.write_str("str");
|
||||
}
|
||||
|
||||
t!(buf, "34helloline\nbar\n");
|
||||
t!(buf, "34helloline\nbar\n☃str");
|
||||
}
|
||||
|
||||
// Just make sure that the macros are defined, there's not really a lot that we
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue