mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
auto merge of #20760 : alexcrichton/rust/rollup, r=alexcrichton
This commit is contained in:
commit
00b112c45a
@ -6,14 +6,14 @@ documentation.
|
||||
## Quick Start
|
||||
|
||||
1. Download a [binary installer][installer] for your platform.
|
||||
2. Read the [guide].
|
||||
2. Read [The Rust Programming Language][trpl].
|
||||
3. Enjoy!
|
||||
|
||||
> ***Note:*** Windows users can read the detailed
|
||||
> [using Rust on Windows][win-wiki] notes on the wiki.
|
||||
|
||||
[installer]: http://www.rust-lang.org/install.html
|
||||
[guide]: http://doc.rust-lang.org/guide.html
|
||||
[trpl]: http://doc.rust-lang.org/book/index.html
|
||||
[win-wiki]: https://github.com/rust-lang/rust/wiki/Using-Rust-on-Windows
|
||||
|
||||
## Building from Source
|
||||
@ -53,7 +53,7 @@ documentation.
|
||||
When complete, `make install` will place several programs into
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool.
|
||||
3. Read the [guide].
|
||||
3. Read [The Rust Programming Language][trpl].
|
||||
4. Enjoy!
|
||||
|
||||
### Building on Windows
|
||||
@ -75,7 +75,7 @@ To easily build on windows we can use [MSYS2](http://sourceforge.net/projects/ms
|
||||
|
||||
[repo]: https://github.com/rust-lang/rust
|
||||
[tarball]: https://static.rust-lang.org/dist/rust-nightly.tar.gz
|
||||
[guide]: http://doc.rust-lang.org/guide.html
|
||||
[trpl]: http://doc.rust-lang.org/book/index.html
|
||||
|
||||
## Notes
|
||||
|
||||
|
@ -19,8 +19,10 @@ Version 1.0.0-alpha (January 2015)
|
||||
distribution into the Cargo ecosystem so they can evolve
|
||||
separately and don't need to be stabilized as quickly, including
|
||||
'time', 'getopts', 'num', 'regex', and 'term'.
|
||||
* Documentation continues to be expanded with more guides, more
|
||||
API coverage and more examples.
|
||||
* Documentation continues to be expanded with more API coverage, more
|
||||
examples, and more in-depth explanations. The guides have been
|
||||
consolidated into [The Rust Programming Language][trpl].
|
||||
* "Rust By Example" is now maintained by the Rust team.
|
||||
* All official Rust binary installers now come with [Cargo], the
|
||||
Rust package manager.
|
||||
|
||||
@ -179,6 +181,7 @@ Version 1.0.0-alpha (January 2015)
|
||||
[objsafe]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
||||
[assoc]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md
|
||||
[ints]: https://github.com/rust-lang/rfcs/pull/544#issuecomment-68760871
|
||||
[trpl]: http://doc.rust-lang.org/book/index.html
|
||||
|
||||
Version 0.12.0 (October 2014)
|
||||
-----------------------------
|
||||
|
12
configure
vendored
12
configure
vendored
@ -1055,18 +1055,6 @@ do
|
||||
make_dir $h/test/debuginfo-gdb
|
||||
make_dir $h/test/debuginfo-lldb
|
||||
make_dir $h/test/codegen
|
||||
make_dir $h/test/doc-guide
|
||||
make_dir $h/test/doc-guide-ffi
|
||||
make_dir $h/test/doc-guide-runtime
|
||||
make_dir $h/test/doc-guide-macros
|
||||
make_dir $h/test/doc-guide-ownership
|
||||
make_dir $h/test/doc-guide-pointers
|
||||
make_dir $h/test/doc-guide-container
|
||||
make_dir $h/test/doc-guide-tasks
|
||||
make_dir $h/test/doc-guide-plugin
|
||||
make_dir $h/test/doc-guide-crates
|
||||
make_dir $h/test/doc-guide-error-handling
|
||||
make_dir $h/test/doc-reference
|
||||
done
|
||||
|
||||
# Configure submodules
|
||||
|
@ -57,7 +57,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm
|
||||
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
TOOLS := compiletest rustdoc rustc
|
||||
TOOLS := compiletest rustdoc rustc rustbook
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_libc := core
|
||||
@ -99,9 +99,11 @@ DEPS_fmt_macros = std
|
||||
TOOL_DEPS_compiletest := test getopts
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
TOOL_DEPS_rustc := rustc_driver
|
||||
TOOL_DEPS_rustbook := std regex rustdoc
|
||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustbook := $(S)src/rustbook/main.rs
|
||||
|
||||
ONLY_RLIB_core := 1
|
||||
ONLY_RLIB_libc := 1
|
||||
|
26
mk/docs.mk
26
mk/docs.mk
@ -9,7 +9,7 @@
|
||||
# except according to those terms.
|
||||
|
||||
######################################################################
|
||||
# The various pieces of standalone documentation: guides, manual, etc
|
||||
# The various pieces of standalone documentation.
|
||||
#
|
||||
# The DOCS variable is their names (with no file extension).
|
||||
#
|
||||
@ -25,13 +25,11 @@
|
||||
# L10N_LANGS are the languages for which the docs have been
|
||||
# translated.
|
||||
######################################################################
|
||||
DOCS := index intro tutorial guide guide-ffi guide-macros guide-ownership \
|
||||
guide-tasks guide-container guide-pointers guide-testing \
|
||||
guide-plugin guide-crates complement-bugreport guide-error-handling \
|
||||
complement-lang-faq complement-design-faq complement-project-faq \
|
||||
rustdoc guide-unsafe guide-strings reference
|
||||
DOCS := index intro tutorial complement-bugreport \
|
||||
complement-lang-faq complement-design-faq complement-project-faq \
|
||||
rustdoc reference
|
||||
|
||||
PDF_DOCS := guide reference
|
||||
PDF_DOCS := reference
|
||||
|
||||
RUSTDOC_DEPS_reference := doc/full-toc.inc
|
||||
RUSTDOC_FLAGS_reference := --html-in-header=doc/full-toc.inc
|
||||
@ -61,9 +59,15 @@ RUSTDOC_EXE = $(HBIN2_H_$(CFG_BUILD))/rustdoc$(X_$(CFG_BUILD))
|
||||
# ./configure
|
||||
RUSTDOC = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTDOC_EXE)
|
||||
|
||||
# The rustbook executable...
|
||||
RUSTBOOK_EXE = $(HBIN2_H_$(CFG_BUILD))/rustbook$(X_$(CFG_BUILD))
|
||||
# ...with rpath included in case --disable-rpath was provided to
|
||||
# ./configure
|
||||
RUSTBOOK = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTBOOK_EXE)
|
||||
|
||||
D := $(S)src/doc
|
||||
|
||||
DOC_TARGETS :=
|
||||
DOC_TARGETS := trpl
|
||||
COMPILER_DOC_TARGETS :=
|
||||
DOC_L10N_TARGETS :=
|
||||
|
||||
@ -270,3 +274,9 @@ endif
|
||||
|
||||
docs: $(DOC_TARGETS)
|
||||
compiler-docs: $(COMPILER_DOC_TARGETS)
|
||||
|
||||
trpl: doc/book/index.html
|
||||
|
||||
doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md)
|
||||
$(Q)rm -rf doc/book
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book
|
||||
|
@ -70,7 +70,7 @@ define PREPARE_MAN
|
||||
$(Q)$(PREPARE_MAN_CMD) $(PREPARE_SOURCE_MAN_DIR)/$(1) $(PREPARE_DEST_MAN_DIR)/$(1)
|
||||
endef
|
||||
|
||||
PREPARE_TOOLS = $(filter-out compiletest, $(TOOLS))
|
||||
PREPARE_TOOLS = $(filter-out compiletest rustbook, $(TOOLS))
|
||||
|
||||
|
||||
# $(1) is tool
|
||||
|
29
mk/tests.mk
29
mk/tests.mk
@ -147,6 +147,17 @@ else
|
||||
CFG_ADB_TEST_DIR=
|
||||
endif
|
||||
|
||||
# $(1) - name of doc test
|
||||
# $(2) - file of the test
|
||||
define DOCTEST
|
||||
DOC_NAMES := $$(DOC_NAMES) $(1)
|
||||
DOCFILE_$(1) := $(2)
|
||||
endef
|
||||
|
||||
$(foreach doc,$(DOCS), \
|
||||
$(eval $(call DOCTEST,md-$(doc),$(S)src/doc/$(doc).md)))
|
||||
$(foreach file,$(wildcard $(S)src/doc/trpl/*.md), \
|
||||
$(eval $(call DOCTEST,$(file:$(S)src/doc/trpl/%.md=trpl-%),$(file))))
|
||||
|
||||
######################################################################
|
||||
# Main test targets
|
||||
@ -292,6 +303,7 @@ tidy:
|
||||
| grep '^$(S)src/rust-installer' -v \
|
||||
| xargs $(CFG_PYTHON) $(S)src/etc/check-binaries.py
|
||||
|
||||
|
||||
endif
|
||||
|
||||
|
||||
@ -339,8 +351,8 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-crate-$$(crate)-exec)
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-exec: \
|
||||
$$(foreach docname,$$(DOCS), \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-$$(docname)-exec)
|
||||
$$(foreach docname,$$(DOC_NAMES), \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-doc-$$(docname)-exec) \
|
||||
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-exec \
|
||||
@ -795,17 +807,18 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3)
|
||||
# rustdoc etc.
|
||||
ifeq ($(NO_REBUILD),)
|
||||
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = \
|
||||
$$(D)/$(4).md \
|
||||
$$(DOCFILE_$(4)) \
|
||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||
$$(RUSTDOC_EXE_$(1)_T_$(2)_H_$(3))
|
||||
else
|
||||
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(D)/$(4).md
|
||||
DOCTESTDEP_$(1)_$(2)_$(3)_$(4) = $$(DOCFILE_$(4))
|
||||
endif
|
||||
|
||||
ifeq ($(2),$$(CFG_BUILD))
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): $$(DOCTESTDEP_$(1)_$(2)_$(3)_$(4))
|
||||
@$$(call E, run doc-$(4) [$(2)])
|
||||
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --cfg dox --test $$< --test-args "$$(TESTARGS)" && touch $$@
|
||||
$$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --cfg dox --test $$< \
|
||||
--test-args "$$(TESTARGS)" && touch $$@
|
||||
else
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)):
|
||||
touch $$@
|
||||
@ -815,7 +828,7 @@ endef
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(foreach docname,$(DOCS), \
|
||||
$(foreach docname,$(DOC_NAMES), \
|
||||
$(eval $(call DEF_DOC_TEST,$(stage),$(target),$(host),$(docname)))))))
|
||||
|
||||
# Crates
|
||||
@ -877,7 +890,7 @@ TEST_GROUPS = \
|
||||
debuginfo-lldb \
|
||||
codegen \
|
||||
doc \
|
||||
$(foreach docname,$(DOCS),doc-$(docname)) \
|
||||
$(foreach docname,$(DOC_NAMES),doc-$(docname)) \
|
||||
pretty \
|
||||
pretty-rpass \
|
||||
pretty-rpass-valgrind \
|
||||
@ -946,7 +959,7 @@ $(foreach stage,$(STAGES), \
|
||||
$(eval $(call DEF_CHECK_FOR_STAGE_AND_HOSTS_AND_GROUP,$(stage),$(host),$(group))))))
|
||||
|
||||
define DEF_CHECK_DOC_FOR_STAGE
|
||||
check-stage$(1)-docs: $$(foreach docname,$$(DOCS), \
|
||||
check-stage$(1)-docs: $$(foreach docname,$$(DOC_NAMES), \
|
||||
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-$$(docname)) \
|
||||
$$(foreach crate,$$(TEST_DOC_CRATES), \
|
||||
check-stage$(1)-T-$$(CFG_BUILD)-H-$$(CFG_BUILD)-doc-crate-$$(crate))
|
||||
|
@ -12,6 +12,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![feature(slicing_syntax, unboxed_closures)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(int_uint)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
% The Rust Containers and Iterators Guide
|
||||
|
||||
This guide has been removed, with no direct replacement.
|
||||
|
||||
You may enjoy reading the [iterator](std/iter/index.html) and
|
||||
[collections](std/collections/index.html) documentation.
|
@ -1,308 +0,0 @@
|
||||
% The Guide to Rust Strings
|
||||
|
||||
Strings are an important concept to master in any programming language. If you
|
||||
come from a managed language background, you may be surprised at the complexity
|
||||
of string handling in a systems programming language. Efficient access and
|
||||
allocation of memory for a dynamically sized structure involves a lot of
|
||||
details. Luckily, Rust has lots of tools to help us here.
|
||||
|
||||
A **string** is a sequence of unicode scalar values encoded as a stream of
|
||||
UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences.
|
||||
Additionally, strings are not null-terminated and can contain null bytes.
|
||||
|
||||
Rust has two main types of strings: `&str` and `String`.
|
||||
|
||||
# &str
|
||||
|
||||
The first kind is a `&str`. This is pronounced a 'string slice'.
|
||||
String literals are of the type `&str`:
|
||||
|
||||
```{rust}
|
||||
let string = "Hello there.";
|
||||
```
|
||||
|
||||
Like any Rust type, string slices have an associated lifetime. A string literal
|
||||
is a `&'static str`. A string slice can be written without an explicit
|
||||
lifetime in many cases, such as in function arguments. In these cases the
|
||||
lifetime will be inferred:
|
||||
|
||||
```{rust}
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
```
|
||||
|
||||
Like vector slices, string slices are simply a pointer plus a length. This
|
||||
means that they're a 'view' into an already-allocated string, such as a
|
||||
`&'static str` or a `String`.
|
||||
|
||||
# String
|
||||
|
||||
A `String` is a heap-allocated string. This string is growable, and is also
|
||||
guaranteed to be UTF-8.
|
||||
|
||||
```{rust}
|
||||
let mut s = "Hello".to_string();
|
||||
println!("{}", s);
|
||||
|
||||
s.push_str(", world.");
|
||||
println!("{}", s);
|
||||
```
|
||||
|
||||
You can coerce a `String` into a `&str` with the `as_slice()` method:
|
||||
|
||||
```{rust}
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(s.as_slice());
|
||||
}
|
||||
```
|
||||
|
||||
You can also get a `&str` from a stack-allocated array of bytes:
|
||||
|
||||
```{rust}
|
||||
use std::str;
|
||||
|
||||
let x: &[u8] = &[b'a', b'b'];
|
||||
let stack_str: &str = str::from_utf8(x).unwrap();
|
||||
```
|
||||
|
||||
# Best Practices
|
||||
|
||||
## `String` vs. `&str`
|
||||
|
||||
In general, you should prefer `String` when you need ownership, and `&str` when
|
||||
you just need to borrow a string. This is very similar to using `Vec<T>` vs. `&[T]`,
|
||||
and `T` vs `&T` in general.
|
||||
|
||||
This means starting off with this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: &str) {
|
||||
```
|
||||
|
||||
and only moving to this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn foo(s: String) {
|
||||
```
|
||||
|
||||
If you have good reason. It's not polite to hold on to ownership you don't
|
||||
need, and it can make your lifetimes more complex.
|
||||
|
||||
## Generic functions
|
||||
|
||||
To write a function that's generic over types of strings, use `&str`.
|
||||
|
||||
```{rust}
|
||||
fn some_string_length(x: &str) -> uint {
|
||||
x.len()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello, world";
|
||||
|
||||
println!("{}", some_string_length(s));
|
||||
|
||||
let s = "Hello, world".to_string();
|
||||
|
||||
println!("{}", some_string_length(s.as_slice()));
|
||||
}
|
||||
```
|
||||
|
||||
Both of these lines will print `12`.
|
||||
|
||||
## Comparisons
|
||||
|
||||
To compare a String to a constant string, prefer `as_slice()`...
|
||||
|
||||
```{rust}
|
||||
fn compare(x: String) {
|
||||
if x.as_slice() == "Hello" {
|
||||
println!("yes");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
... over `to_string()`:
|
||||
|
||||
```{rust}
|
||||
fn compare(x: String) {
|
||||
if x == "Hello".to_string() {
|
||||
println!("yes");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Converting a `String` to a `&str` is cheap, but converting the `&str` to a
|
||||
`String` involves an allocation.
|
||||
|
||||
## Indexing strings
|
||||
|
||||
You may be tempted to try to access a certain character of a `String`, like
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
let s = "hello".to_string();
|
||||
|
||||
println!("{}", s[0]);
|
||||
```
|
||||
|
||||
This does not compile. This is on purpose. In the world of UTF-8, direct
|
||||
indexing is basically never what you want to do. The reason is that each
|
||||
character can be a variable number of bytes. This means that you have to iterate
|
||||
through the characters anyway, which is an O(n) operation.
|
||||
|
||||
There's 3 basic levels of unicode (and its encodings):
|
||||
|
||||
- code units, the underlying data type used to store everything
|
||||
- code points/unicode scalar values (char)
|
||||
- graphemes (visible characters)
|
||||
|
||||
Rust provides iterators for each of these situations:
|
||||
|
||||
- `.bytes()` will iterate over the underlying bytes
|
||||
- `.chars()` will iterate over the code points
|
||||
- `.graphemes()` will iterate over each grapheme
|
||||
|
||||
Usually, the `graphemes()` method on `&str` is what you want:
|
||||
|
||||
```{rust}
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.graphemes(true) {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```{text}
|
||||
u͔
|
||||
n͈̰̎
|
||||
i̙̮͚̦
|
||||
c͚̉
|
||||
o̼̩̰͗
|
||||
d͔̆̓ͥ
|
||||
é
|
||||
```
|
||||
|
||||
Note that `l` has the type `&str` here, since a single grapheme can consist of
|
||||
multiple codepoints, so a `char` wouldn't be appropriate.
|
||||
|
||||
This will print out each visible character in turn, as you'd expect: first "u͔", then
|
||||
"n͈̰̎", etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`:
|
||||
|
||||
```{rust}
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.chars() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This prints:
|
||||
|
||||
```{text}
|
||||
u
|
||||
͔
|
||||
n
|
||||
̎
|
||||
͈
|
||||
̰
|
||||
i
|
||||
̙
|
||||
̮
|
||||
͚
|
||||
̦
|
||||
c
|
||||
̉
|
||||
͚
|
||||
o
|
||||
͗
|
||||
̼
|
||||
̩
|
||||
̰
|
||||
d
|
||||
̆
|
||||
̓
|
||||
ͥ
|
||||
͔
|
||||
e
|
||||
́
|
||||
```
|
||||
|
||||
You can see how some of them are combining characters, and therefore the output
|
||||
looks a bit odd.
|
||||
|
||||
If you want the individual byte representation of each codepoint, you can use
|
||||
`.bytes()`:
|
||||
|
||||
```{rust}
|
||||
let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé";
|
||||
|
||||
for l in s.bytes() {
|
||||
println!("{}", l);
|
||||
}
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
```{text}
|
||||
117
|
||||
205
|
||||
148
|
||||
110
|
||||
204
|
||||
142
|
||||
205
|
||||
136
|
||||
204
|
||||
176
|
||||
105
|
||||
204
|
||||
153
|
||||
204
|
||||
174
|
||||
205
|
||||
154
|
||||
204
|
||||
166
|
||||
99
|
||||
204
|
||||
137
|
||||
205
|
||||
154
|
||||
111
|
||||
205
|
||||
151
|
||||
204
|
||||
188
|
||||
204
|
||||
169
|
||||
204
|
||||
176
|
||||
100
|
||||
204
|
||||
134
|
||||
205
|
||||
131
|
||||
205
|
||||
165
|
||||
205
|
||||
148
|
||||
101
|
||||
204
|
||||
129
|
||||
```
|
||||
|
||||
Many more bytes than graphemes!
|
||||
|
||||
# Other Documentation
|
||||
|
||||
* [the `&str` API documentation](std/str/index.html)
|
||||
* [the `String` API documentation](std/string/index.html)
|
5520
src/doc/guide.md
5520
src/doc/guide.md
File diff suppressed because it is too large
Load Diff
@ -9,10 +9,11 @@ If you haven't seen Rust at all yet, the first thing you should read is the [30
|
||||
minute intro](intro.html). It will give you an overview of the basic ideas of Rust
|
||||
at a high level.
|
||||
|
||||
Once you know you really want to learn Rust, the next step is reading [the
|
||||
guide](guide.html). It is a lengthy explanation of Rust, its syntax, and its
|
||||
concepts. Upon completing the guide, you'll be an intermediate Rust developer,
|
||||
and will have a good grasp of the fundamental ideas behind Rust.
|
||||
Once you know you really want to learn Rust, the next step is reading [The
|
||||
Rust Programming Language](book/index.html). It is a lengthy explanation of
|
||||
Rust, its syntax, and its concepts. Upon completing the book, you'll be an
|
||||
intermediate Rust developer, and will have a good grasp of the fundamental
|
||||
ideas behind Rust.
|
||||
|
||||
# Community & Getting Help
|
||||
|
||||
@ -48,24 +49,6 @@ development of Rust itself is discussed.
|
||||
Rust does not have an exact specification, but an effort to describe as much of
|
||||
the language in as much detail as possible is in [the reference](reference.html).
|
||||
|
||||
# Guides
|
||||
|
||||
Rust Guides are in-depth looks at a particular topic that's relevant to Rust
|
||||
development. If you're trying to figure out how to do something, there may be
|
||||
a guide that can help you out:
|
||||
|
||||
* [Ownership](guide-ownership.html)
|
||||
* [Strings](guide-strings.html)
|
||||
* [Pointers](guide-pointers.html)
|
||||
* [Crates and modules](guide-crates.html)
|
||||
* [Threads and Communication](guide-tasks.html)
|
||||
* [Error Handling](guide-error-handling.html)
|
||||
* [Foreign Function Interface](guide-ffi.html)
|
||||
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
|
||||
* [Macros](guide-macros.html)
|
||||
* [Testing](guide-testing.html)
|
||||
* [Compiler Plugins](guide-plugin.html)
|
||||
|
||||
# Tools
|
||||
|
||||
Rust's still a young language, so there isn't a ton of tooling yet, but the
|
||||
|
@ -7,8 +7,8 @@ This introduction will give you a rough idea of what Rust is like, eliding many
|
||||
details. It does not require prior experience with systems programming, but you
|
||||
may find the syntax easier if you've used a 'curly brace' programming language
|
||||
before, like C or JavaScript. The concepts are more important than the syntax,
|
||||
so don't worry if you don't get every last detail: you can read [the
|
||||
Guide](guide.html) to get a more complete explanation.
|
||||
so don't worry if you don't get every last detail: you can read [The
|
||||
Rust Programming Language](book/index.html) to get a more complete explanation.
|
||||
|
||||
Because this is about high-level concepts, you don't need to actually install
|
||||
Rust to follow along. If you'd like to anyway, check out [the
|
||||
@ -587,5 +587,6 @@ the type system helps you find bugs, how Rust can help you write correct
|
||||
concurrent code, and how you don't have to pay a speed cost for much of this
|
||||
safety.
|
||||
|
||||
To continue your Rustic education, read [the guide](guide.html) for a more
|
||||
in-depth exploration of Rust's syntax and concepts.
|
||||
To continue your Rustic education, read [The Rust Programming
|
||||
Language](book/index.html) for a more in-depth exploration of Rust's syntax and
|
||||
concepts.
|
||||
|
@ -14,7 +14,7 @@ provides three kinds of material:
|
||||
influenced the design.
|
||||
|
||||
This document does not serve as an introduction to the language. Background
|
||||
familiarity with the language is assumed. A separate [guide] is available to
|
||||
familiarity with the language is assumed. A separate [book] is available to
|
||||
help acquire such background familiarity.
|
||||
|
||||
This document also does not serve as a reference to the [standard] library
|
||||
@ -23,7 +23,7 @@ separately by extracting documentation attributes from their source code. Many
|
||||
of the features that one might expect to be language features are library
|
||||
features in Rust, so what you're looking for may be there, not here.
|
||||
|
||||
[guide]: guide.html
|
||||
[book]: book/index.html
|
||||
[standard]: std/index.html
|
||||
|
||||
# Notation
|
||||
@ -647,10 +647,10 @@ All of the above extensions are expressions with values.
|
||||
|
||||
Users of `rustc` can define new syntax extensions in two ways:
|
||||
|
||||
* [Compiler plugins](guide-plugin.html#syntax-extensions) can include arbitrary
|
||||
* [Compiler plugins](book/syntax-extensions.html) can include arbitrary
|
||||
Rust code that manipulates syntax trees at compile time.
|
||||
|
||||
* [Macros](guide-macros.html) define new syntax in a higher-level,
|
||||
* [Macros](book/macros.html) define new syntax in a higher-level,
|
||||
declarative way.
|
||||
|
||||
## Macros
|
||||
@ -2076,7 +2076,7 @@ On `struct`s:
|
||||
list of names `#[macro_use(foo, bar)]` restricts the import to just those
|
||||
macros named. The `extern crate` must appear at the crate root, not inside
|
||||
`mod`, which ensures proper function of the [`$crate` macro
|
||||
variable](guide-macros.html#the-variable-$crate).
|
||||
variable](book/macros.html#the-variable-$crate).
|
||||
|
||||
- `macro_reexport` on an `extern crate` — re-export the named macros.
|
||||
|
||||
@ -2090,8 +2090,9 @@ On `struct`s:
|
||||
- `no_link` on an `extern crate` — even if we load this crate for macros or
|
||||
compiler plugins, don't link it into the output.
|
||||
|
||||
See the [macros guide](guide-macros.html#scoping-and-macro-import/export) for
|
||||
more information on macro scope.
|
||||
See the [macros section of the
|
||||
book](book/macros.html#scoping-and-macro-import/export) for more information on
|
||||
macro scope.
|
||||
|
||||
|
||||
### Miscellaneous attributes
|
||||
@ -2193,7 +2194,7 @@ For any lint check `C`:
|
||||
|
||||
The lint checks supported by the compiler can be found via `rustc -W help`,
|
||||
along with their default settings. [Compiler
|
||||
plugins](guide-plugin.html#lint-plugins) can provide additional lint checks.
|
||||
plugins](book/plugin.html#lint-plugins) can provide additional lint checks.
|
||||
|
||||
```{.ignore}
|
||||
mod m1 {
|
||||
@ -4227,7 +4228,7 @@ communication facilities.
|
||||
The Rust compiler supports various methods to link crates together both
|
||||
statically and dynamically. This section will explore the various methods to
|
||||
link Rust crates together, and more information about native libraries can be
|
||||
found in the [ffi guide][ffi].
|
||||
found in the [ffi section of the book][ffi].
|
||||
|
||||
In one session of compilation, the compiler can generate multiple artifacts
|
||||
through the usage of either command line flags or the `crate_type` attribute.
|
||||
@ -4359,5 +4360,5 @@ that have since been removed):
|
||||
* [Unicode Annex #31](http://www.unicode.org/reports/tr31/): identifier and
|
||||
pattern syntax
|
||||
|
||||
[ffi]: guide-ffi.html
|
||||
[plugin]: guide-plugin.html
|
||||
[ffi]: book/ffi.html
|
||||
[plugin]: book/plugin.html
|
||||
|
35
src/doc/trpl/README.md
Normal file
35
src/doc/trpl/README.md
Normal file
@ -0,0 +1,35 @@
|
||||
% The Rust Programming Language
|
||||
|
||||
Welcome! This book will teach you about [the Rust Programming
|
||||
Language](http://www.rust-lang.org/). Rust is a modern systems programming
|
||||
language focusing on safety and speed. It accomplishes these goals by being
|
||||
memory safe without using garbage collection.
|
||||
|
||||
"The Rust Programming Language" is split into three sections, which you can
|
||||
navigate through the menu on the left.
|
||||
|
||||
## Basics
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax, and cumulates
|
||||
in a small project: a guessing game.
|
||||
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
||||
|
||||
## Intermediate
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
||||
|
||||
## Advanced
|
||||
|
||||
In a similar fashion to "Intermediate," this setion is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
chapters focus on the most complex features, as well as some things that
|
||||
are only available in upcoming versions of Rust.
|
||||
|
||||
After reading "Advanced," you'll be a Rust expert!
|
36
src/doc/trpl/SUMMARY.md
Normal file
36
src/doc/trpl/SUMMARY.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Summary
|
||||
|
||||
* [I: The Basics](basic.md)
|
||||
* [Installing Rust](installing-rust.md)
|
||||
* [Hello, world!](hello-world.md)
|
||||
* [Hello, Cargo!](hello-cargo.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [If](if.md)
|
||||
* [Functions](functions.md)
|
||||
* [Comments](comments.md)
|
||||
* [Compound Data Types](compound-data-types.md)
|
||||
* [Match](match.md)
|
||||
* [Looping](looping.md)
|
||||
* [Strings](strings.md)
|
||||
* [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md)
|
||||
* [Standard Input](standard-input.md)
|
||||
* [Guessing Game](guessing-game.md)
|
||||
* [II: Intermediate Rust](intermediate.md)
|
||||
* [Crates and Modules](crates-and-modules.md)
|
||||
* [Testing](testing.md)
|
||||
* [Pointers](pointers.md)
|
||||
* [Ownership](ownership.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Closures](closures.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Tasks](tasks.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [III: Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Unsafe Code](unsafe.md)
|
||||
* [Macros](macros.md)
|
||||
* [Compiler Plugins](plugins.md)
|
||||
* [Conclusion](conclusion.md)
|
8
src/doc/trpl/advanced.md
Normal file
8
src/doc/trpl/advanced.md
Normal file
@ -0,0 +1,8 @@
|
||||
% Advanced
|
||||
|
||||
In a similar fashion to "Intermediate," this setion is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
chapters focus on the most complex features, as well as some things that
|
||||
are only available in upcoming versions of Rust.
|
||||
|
||||
After reading "Advanced," you'll be a Rust expert!
|
99
src/doc/trpl/arrays-vectors-and-slices.md
Normal file
99
src/doc/trpl/arrays-vectors-and-slices.md
Normal file
@ -0,0 +1,99 @@
|
||||
% Arrays, Vectors, and Slices
|
||||
|
||||
Like many programming languages, Rust has list types to represent a sequence of
|
||||
things. The most basic is the **array**, a fixed-size list of elements of the
|
||||
same type. By default, arrays are immutable.
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3]; // a: [i32; 3]
|
||||
let mut m = [1, 2, 3]; // mut m: [i32; 3]
|
||||
```
|
||||
|
||||
There's a shorthand for initializing each element of an array to the same
|
||||
value. In this example, each element of `a` will be initialized to `0`:
|
||||
|
||||
```{rust}
|
||||
let a = [0; 20]; // a: [i32; 20]
|
||||
```
|
||||
|
||||
Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we
|
||||
cover generics.
|
||||
|
||||
You can get the number of elements in an array `a` with `a.len()`, and use
|
||||
`a.iter()` to iterate over them with a for loop. This code will print each
|
||||
number in order:
|
||||
|
||||
```{rust}
|
||||
let a = [1, 2, 3];
|
||||
|
||||
println!("a has {} elements", a.len());
|
||||
for e in a.iter() {
|
||||
println!("{}", e);
|
||||
}
|
||||
```
|
||||
|
||||
You can access a particular element of an array with **subscript notation**:
|
||||
|
||||
```{rust}
|
||||
let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3]
|
||||
|
||||
println!("The second name is: {}", names[1]);
|
||||
```
|
||||
|
||||
Subscripts start at zero, like in most programming languages, so the first name
|
||||
is `names[0]` and the second name is `names[1]`. The above example prints
|
||||
`The second name is: Brian`. If you try to use a subscript that is not in the
|
||||
array, you will get an error: array access is bounds-checked at run-time. Such
|
||||
errant access is the source of many bugs in other systems programming
|
||||
languages.
|
||||
|
||||
A **vector** is a dynamic or "growable" array, implemented as the standard
|
||||
library type [`Vec<T>`](../std/vec/) (we'll talk about what the `<T>` means
|
||||
later). Vectors are to arrays what `String` is to `&str`. You can create them
|
||||
with the `vec!` macro:
|
||||
|
||||
```{rust}
|
||||
let v = vec![1, 2, 3]; // v: Vec<i32>
|
||||
```
|
||||
|
||||
(Notice that unlike the `println!` macro we've used in the past, we use square
|
||||
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
|
||||
this is just convention.)
|
||||
|
||||
You can get the length of, iterate over, and subscript vectors just like
|
||||
arrays. In addition, (mutable) vectors can grow automatically:
|
||||
|
||||
```{rust}
|
||||
let mut nums = vec![1, 2, 3]; // mut nums: Vec<i32>
|
||||
|
||||
nums.push(4);
|
||||
|
||||
println!("The length of nums is now {}", nums.len()); // Prints 4
|
||||
```
|
||||
|
||||
Vectors have many more useful methods.
|
||||
|
||||
A **slice** is a reference to (or "view" into) an array. They are useful for
|
||||
allowing safe, efficient access to a portion of an array without copying. For
|
||||
example, you might want to reference just one line of a file read into memory.
|
||||
By nature, a slice is not created directly, but from an existing variable.
|
||||
Slices have a length, can be mutable or not, and in many ways behave like
|
||||
arrays:
|
||||
|
||||
```{rust}
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3]
|
||||
|
||||
for e in middle.iter() {
|
||||
println!("{}", e); // Prints 1, 2, 3
|
||||
}
|
||||
```
|
||||
|
||||
You can also take a slice of a vector, `String`, or `&str`, because they are
|
||||
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
|
||||
generics.
|
||||
|
||||
We have now learned all of the most basic Rust concepts. We're ready to start
|
||||
building our guessing game, we just need to know one last thing: how to get
|
||||
input from the keyboard. You can't have a guessing game without the ability to
|
||||
guess!
|
8
src/doc/trpl/basic.md
Normal file
8
src/doc/trpl/basic.md
Normal file
@ -0,0 +1,8 @@
|
||||
% Basics
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax, and cumulates
|
||||
in a small project: a guessing game.
|
||||
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
185
src/doc/trpl/closures.md
Normal file
185
src/doc/trpl/closures.md
Normal file
@ -0,0 +1,185 @@
|
||||
% Closures
|
||||
|
||||
So far, we've made lots of functions in Rust, but we've given them all names.
|
||||
Rust also allows us to create anonymous functions. Rust's anonymous
|
||||
functions are called **closure**s. By themselves, closures aren't all that
|
||||
interesting, but when you combine them with functions that take closures as
|
||||
arguments, really powerful things are possible.
|
||||
|
||||
Let's make a closure:
|
||||
|
||||
```{rust}
|
||||
let add_one = |&: x| { 1 + x };
|
||||
|
||||
println!("The sum of 5 plus 1 is {}.", add_one(5));
|
||||
```
|
||||
|
||||
We create a closure using the `|...| { ... }` syntax, and then we create a
|
||||
binding so we can use it later. Note that we call the function using the
|
||||
binding name and two parentheses, just like we would for a named function.
|
||||
|
||||
Let's compare syntax. The two are pretty close:
|
||||
|
||||
```{rust}
|
||||
let add_one = |&: x: i32| -> i32 { 1 + x };
|
||||
fn add_one (x: i32) -> i32 { 1 + x }
|
||||
```
|
||||
|
||||
As you may have noticed, closures infer their argument and return types, so you
|
||||
don't need to declare one. This is different from named functions, which
|
||||
default to returning unit (`()`).
|
||||
|
||||
There's one big difference between a closure and named functions, and it's in
|
||||
the name: a closure "closes over its environment." What does that mean? It means
|
||||
this:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let x: i32 = 5;
|
||||
|
||||
let printer = |&:| { println!("x is: {}", x); };
|
||||
|
||||
printer(); // prints "x is: 5"
|
||||
}
|
||||
```
|
||||
|
||||
The `||` syntax means this is an anonymous closure that takes no arguments.
|
||||
Without it, we'd just have a block of code in `{}`s.
|
||||
|
||||
In other words, a closure has access to variables in the scope where it's
|
||||
defined. The closure borrows any variables it uses, so this will error:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
let printer = |&:| { println!("x is: {}", x); };
|
||||
|
||||
x = 6; // error: cannot assign to `x` because it is borrowed
|
||||
}
|
||||
```
|
||||
|
||||
## Moving closures
|
||||
|
||||
Rust has a second type of closure, called a **moving closure**. Moving
|
||||
closures are indicated using the `move` keyword (e.g., `move || x *
|
||||
x`). The difference between a moving closure and an ordinary closure
|
||||
is that a moving closure always takes ownership of all variables that
|
||||
it uses. Ordinary closures, in contrast, just create a reference into
|
||||
the enclosing stack frame. Moving closures are most useful with Rust's
|
||||
concurrency features, and so we'll just leave it at this for
|
||||
now. We'll talk about them more in the "Threads" section of the guide.
|
||||
|
||||
## Accepting closures as arguments
|
||||
|
||||
Closures are most useful as an argument to another function. Here's an example:
|
||||
|
||||
```{rust}
|
||||
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
|
||||
f(x) + f(x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let square = |&: x: i32| { x * x };
|
||||
|
||||
twice(5, square); // evaluates to 50
|
||||
}
|
||||
```
|
||||
|
||||
Let's break the example down, starting with `main`:
|
||||
|
||||
```{rust}
|
||||
let square = |&: x: i32| { x * x };
|
||||
```
|
||||
|
||||
We've seen this before. We make a closure that takes an integer, and returns
|
||||
its square.
|
||||
|
||||
```{rust}
|
||||
# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
|
||||
# let square = |&: x: i32| { x * x };
|
||||
twice(5, square); // evaluates to 50
|
||||
```
|
||||
|
||||
This line is more interesting. Here, we call our function, `twice`, and we pass
|
||||
it two arguments: an integer, `5`, and our closure, `square`. This is just like
|
||||
passing any other two variable bindings to a function, but if you've never
|
||||
worked with closures before, it can seem a little complex. Just think: "I'm
|
||||
passing two variables: one is an i32, and one is a function."
|
||||
|
||||
Next, let's look at how `twice` is defined:
|
||||
|
||||
```{rust,ignore}
|
||||
fn twice(x: i32, f: |i32| -> i32) -> i32 {
|
||||
```
|
||||
|
||||
`twice` takes two arguments, `x` and `f`. That's why we called it with two
|
||||
arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function,
|
||||
though, and that function takes an `i32` and returns an `i32`. Notice
|
||||
how the `|i32| -> i32` syntax looks a lot like our definition of `square`
|
||||
above, if we added the return type in:
|
||||
|
||||
```{rust}
|
||||
let square = |&: x: i32| -> i32 { x * x };
|
||||
// |i32| -> i32
|
||||
```
|
||||
|
||||
This function takes an `i32` and returns an `i32`.
|
||||
|
||||
This is the most complicated function signature we've seen yet! Give it a read
|
||||
a few times until you can see how it works. It takes a teeny bit of practice, and
|
||||
then it's easy.
|
||||
|
||||
Finally, `twice` returns an `i32` as well.
|
||||
|
||||
Okay, let's look at the body of `twice`:
|
||||
|
||||
```{rust}
|
||||
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
|
||||
f(x) + f(x)
|
||||
}
|
||||
```
|
||||
|
||||
Since our closure is named `f`, we can call it just like we called our closures
|
||||
before, and we pass in our `x` argument to each one, hence the name `twice`.
|
||||
|
||||
If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get.
|
||||
|
||||
Play around with this concept until you're comfortable with it. Rust's standard
|
||||
library uses lots of closures where appropriate, so you'll be using
|
||||
this technique a lot.
|
||||
|
||||
If we didn't want to give `square` a name, we could just define it inline.
|
||||
This example is the same as the previous one:
|
||||
|
||||
```{rust}
|
||||
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
|
||||
f(x) + f(x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
twice(5, |x: i32| { x * x }); // evaluates to 50
|
||||
}
|
||||
```
|
||||
|
||||
A named function's name can be used wherever you'd use a closure. Another
|
||||
way of writing the previous example:
|
||||
|
||||
```{rust}
|
||||
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
|
||||
f(x) + f(x)
|
||||
}
|
||||
|
||||
fn square(x: i32) -> i32 { x * x }
|
||||
|
||||
fn main() {
|
||||
twice(5, square); // evaluates to 50
|
||||
}
|
||||
```
|
||||
|
||||
Doing this is not particularly common, but it's useful every once in a while.
|
||||
|
||||
That's all you need to get the hang of closures! Closures are a little bit
|
||||
strange at first, but once you're used to them, you'll miss them
|
||||
in other languages. Passing functions to other functions is
|
||||
incredibly powerful, as you will see in the following chapter about iterators.
|
46
src/doc/trpl/comments.md
Normal file
46
src/doc/trpl/comments.md
Normal file
@ -0,0 +1,46 @@
|
||||
% Comments
|
||||
|
||||
Now that we have some functions, it's a good idea to learn about comments.
|
||||
Comments are notes that you leave to other programmers to help explain things
|
||||
about your code. The compiler mostly ignores them.
|
||||
|
||||
Rust has two kinds of comments that you should care about: **line comment**s
|
||||
and **doc comment**s.
|
||||
|
||||
```{rust}
|
||||
// Line comments are anything after '//' and extend to the end of the line.
|
||||
|
||||
let x = 5; // this is also a line comment.
|
||||
|
||||
// If you have a long explanation for something, you can put line comments next
|
||||
// to each other. Put a space between the // and your comment so that it's
|
||||
// more readable.
|
||||
```
|
||||
|
||||
The other kind of comment is a doc comment. Doc comments use `///` instead of
|
||||
`//`, and support Markdown notation inside:
|
||||
|
||||
```{rust}
|
||||
/// `hello` is a function that prints a greeting that is personalized based on
|
||||
/// the name given.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name of the person you'd like to greet.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let name = "Steve";
|
||||
/// hello(name); // prints "Hello, Steve!"
|
||||
/// ```
|
||||
fn hello(name: &str) {
|
||||
println!("Hello, {}!", name);
|
||||
}
|
||||
```
|
||||
|
||||
When writing doc comments, adding sections for any arguments, return values,
|
||||
and providing some examples of usage is very, very helpful.
|
||||
|
||||
You can use the [`rustdoc`](../rustdoc.html) tool to generate HTML documentation
|
||||
from these doc comments.
|
353
src/doc/trpl/compound-data-types.md
Normal file
353
src/doc/trpl/compound-data-types.md
Normal file
@ -0,0 +1,353 @@
|
||||
% Compound Data Types
|
||||
|
||||
Rust, like many programming languages, has a number of different data types
|
||||
that are built-in. You've already done some simple work with integers and
|
||||
strings, but next, let's talk about some more complicated ways of storing data.
|
||||
|
||||
## Tuples
|
||||
|
||||
The first compound data type we're going to talk about are called **tuple**s.
|
||||
Tuples are an ordered list of a fixed size. Like this:
|
||||
|
||||
```rust
|
||||
let x = (1, "hello");
|
||||
```
|
||||
|
||||
The parentheses and commas form this two-length tuple. Here's the same code, but
|
||||
with the type annotated:
|
||||
|
||||
```rust
|
||||
let x: (i32, &str) = (1, "hello");
|
||||
```
|
||||
|
||||
As you can see, the type of a tuple looks just like the tuple, but with each
|
||||
position having a type name rather than the value. Careful readers will also
|
||||
note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple.
|
||||
You haven't seen `&str` as a type before, and we'll discuss the details of
|
||||
strings later. In systems programming languages, strings are a bit more complex
|
||||
than in other languages. For now, just read `&str` as "a string slice," and
|
||||
we'll learn more soon.
|
||||
|
||||
You can access the fields in a tuple through a **destructuring let**. Here's
|
||||
an example:
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
||||
println!("x is {}", x);
|
||||
```
|
||||
|
||||
Remember before when I said the left-hand side of a `let` statement was more
|
||||
powerful than just assigning a binding? Here we are. We can put a pattern on
|
||||
the left-hand side of the `let`, and if it matches up to the right-hand side,
|
||||
we can assign multiple bindings at once. In this case, `let` 'destructures,'
|
||||
or 'breaks up,' the tuple, and assigns the bits to three bindings.
|
||||
|
||||
This pattern is very powerful, and we'll see it repeated more later.
|
||||
|
||||
There are also a few things you can do with a tuple as a whole, without
|
||||
destructuring. You can assign one tuple into another, if they have the same
|
||||
arity and contained types.
|
||||
|
||||
```rust
|
||||
let mut x = (1, 2); // x: (i32, i32)
|
||||
let y = (2, 3); // y: (i32, i32)
|
||||
|
||||
x = y;
|
||||
```
|
||||
|
||||
You can also check for equality with `==`. Again, this will only compile if the
|
||||
tuples have the same type.
|
||||
|
||||
```rust
|
||||
let x = (1, 2, 3);
|
||||
let y = (2, 2, 4);
|
||||
|
||||
if x == y {
|
||||
println!("yes");
|
||||
} else {
|
||||
println!("no");
|
||||
}
|
||||
```
|
||||
|
||||
This will print `no`, because some of the values aren't equal.
|
||||
|
||||
One other use of tuples is to return multiple values from a function:
|
||||
|
||||
```rust
|
||||
fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) }
|
||||
|
||||
fn main() {
|
||||
let (x, y) = next_two(5);
|
||||
println!("x, y = {}, {}", x, y);
|
||||
}
|
||||
```
|
||||
|
||||
Even though Rust functions can only return one value, a tuple _is_ one value,
|
||||
that happens to be made up of more than one value. You can also see in this example how you
|
||||
can destructure a pattern returned by a function, as well.
|
||||
|
||||
Tuples are a very simple data structure, and so are not often what you want.
|
||||
Let's move on to their bigger sibling, structs.
|
||||
|
||||
## Structs
|
||||
|
||||
A struct is another form of a 'record type,' just like a tuple. There's a
|
||||
difference: structs give each element that they contain a name, called a
|
||||
'field' or a 'member.' Check it out:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let origin = Point { x: 0, y: 0 }; // origin: Point
|
||||
|
||||
println!("The origin is at ({}, {})", origin.x, origin.y);
|
||||
}
|
||||
```
|
||||
|
||||
There's a lot going on here, so let's break it down. We declare a struct with
|
||||
the `struct` keyword, and then with a name. By convention, structs begin with a
|
||||
capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn't need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```{rust}
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut point = Point { x: 0, y: 0 };
|
||||
|
||||
point.x = 5;
|
||||
|
||||
println!("The point is at ({}, {})", point.x, point.y);
|
||||
}
|
||||
```
|
||||
|
||||
This will print `The point is at (5, 0)`.
|
||||
|
||||
## Tuple Structs and Newtypes
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a **tuple struct**. Tuple structs do have a name, but their fields
|
||||
don't:
|
||||
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this a 'newtype,' because it lets
|
||||
you create a new type that's a synonym for another one:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`.
|
||||
|
||||
## Enums
|
||||
|
||||
Finally, Rust has a "sum type", an **enum**. Enums are an incredibly useful
|
||||
feature of Rust, and are used throughout the standard library. This is an enum
|
||||
that is provided by the Rust standard library:
|
||||
|
||||
```{rust}
|
||||
enum Ordering {
|
||||
Less,
|
||||
Equal,
|
||||
Greater,
|
||||
}
|
||||
```
|
||||
|
||||
An `Ordering` can only be _one_ of `Less`, `Equal`, or `Greater` at any given
|
||||
time.
|
||||
|
||||
Because `Ordering` is provided by the standard library, we can use the `use`
|
||||
keyword to use it in our code. We'll learn more about `use` later, but it's
|
||||
used to bring names into scope.
|
||||
|
||||
Here's an example of how to use `Ordering`:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y); // ordering: Ordering
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There's a symbol here we haven't seen before: the double colon (`::`).
|
||||
This is used to indicate a namespace. In this case, `Ordering` lives in
|
||||
the `cmp` submodule of the `std` module. We'll talk more about modules
|
||||
later in the guide. For now, all you need to know is that you can `use`
|
||||
things from the standard library if you need them.
|
||||
|
||||
Okay, let's talk about the actual code in the example. `cmp` is a function that
|
||||
compares two things, and returns an `Ordering`. We return either
|
||||
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on if
|
||||
the two values are greater, less, or equal. Note that each variant of the
|
||||
`enum` is namespaced under the `enum` itself: it's `Ordering::Greater` not
|
||||
`Greater`.
|
||||
|
||||
The `ordering` variable has the type `Ordering`, and so contains one of the
|
||||
three values. We can then do a bunch of `if`/`else` comparisons to check which
|
||||
one it is. However, repeated `if`/`else` comparisons get quite tedious. Rust
|
||||
has a feature that not only makes them nicer to read, but also makes sure that
|
||||
you never miss a case. Before we get to that, though, let's talk about another
|
||||
kind of enum: one with values.
|
||||
|
||||
This enum has two variants, one of which has a value:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
```
|
||||
|
||||
This enum represents an `i32` that we may or may not have. In the `Missing`
|
||||
case, we have no value, but in the `Value` case, we do. This enum is specific
|
||||
to `i32`s, though. We can make it usable by any type, but we haven't quite
|
||||
gotten there yet!
|
||||
|
||||
You can also have any number of values in an enum:
|
||||
|
||||
```{rust}
|
||||
enum OptionalColor {
|
||||
Color(i32, i32, i32),
|
||||
Missing,
|
||||
}
|
||||
```
|
||||
|
||||
And you can also have something like this:
|
||||
|
||||
```{rust}
|
||||
enum StringResult {
|
||||
StringOK(String),
|
||||
ErrorReason(String),
|
||||
}
|
||||
```
|
||||
Where a `StringResult` is either a `StringResult::StringOK`, with the result of
|
||||
a computation, or an `StringResult::ErrorReason` with a `String` explaining
|
||||
what caused the computation to fail. These kinds of `enum`s are actually very
|
||||
useful and are even part of the standard library.
|
||||
|
||||
Here is an example of using our `StringResult`:
|
||||
|
||||
```rust
|
||||
enum StringResult {
|
||||
StringOK(String),
|
||||
ErrorReason(String),
|
||||
}
|
||||
|
||||
fn respond(greeting: &str) -> StringResult {
|
||||
if greeting == "Hello" {
|
||||
StringResult::StringOK("Good morning!".to_string())
|
||||
} else {
|
||||
StringResult::ErrorReason("I didn't understand you!".to_string())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That's a lot of typing! We can use the `use` keyword to make it shorter:
|
||||
|
||||
```rust
|
||||
use StringResult::StringOK;
|
||||
use StringResult::ErrorReason;
|
||||
|
||||
enum StringResult {
|
||||
StringOK(String),
|
||||
ErrorReason(String),
|
||||
}
|
||||
|
||||
# fn main() {}
|
||||
|
||||
fn respond(greeting: &str) -> StringResult {
|
||||
if greeting == "Hello" {
|
||||
StringOK("Good morning!".to_string())
|
||||
} else {
|
||||
ErrorReason("I didn't understand you!".to_string())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`use` declarations must come before anything else, which looks a little strange in this example,
|
||||
since we `use` the variants before we define them. Anyway, in the body of `respond`, we can just
|
||||
say `StringOK` now, rather than the full `StringResult::StringOK`. Importing variants can be
|
||||
convenient, but can also cause name conflicts, so do this with caution. It's considered good style
|
||||
to rarely import variants for this reason.
|
||||
|
||||
As you can see, `enum`s with values are quite a powerful tool for data representation,
|
||||
and can be even more useful when they're generic across types. Before we get to generics,
|
||||
though, let's talk about how to use them with pattern matching, a tool that will
|
||||
let us deconstruct this sum type (the type theory term for enums) in a very elegant
|
||||
way and avoid all these messy `if`/`else`s.
|
10
src/doc/trpl/conclusion.md
Normal file
10
src/doc/trpl/conclusion.md
Normal file
@ -0,0 +1,10 @@
|
||||
% Conclusion
|
||||
|
||||
We covered a lot of ground here. When you've mastered everything in this Guide,
|
||||
you will have a firm grasp of basic Rust development. There's a whole lot more
|
||||
out there, we've just covered the surface. There's tons of topics that you can
|
||||
dig deeper into, and we've built specialized guides for many of them. To learn
|
||||
more, dig into the [full documentation
|
||||
index](index.html).
|
||||
|
||||
Happy hacking!
|
146
src/doc/trpl/functions.md
Normal file
146
src/doc/trpl/functions.md
Normal file
@ -0,0 +1,146 @@
|
||||
% Functions
|
||||
|
||||
You've already seen one function so far, the `main` function:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
This is the simplest possible function declaration. As we mentioned before,
|
||||
`fn` says 'this is a function,' followed by the name, some parentheses because
|
||||
this function takes no arguments, and then some curly braces to indicate the
|
||||
body. Here's a function named `foo`:
|
||||
|
||||
```{rust}
|
||||
fn foo() {
|
||||
}
|
||||
```
|
||||
|
||||
So, what about taking arguments? Here's a function that prints a number:
|
||||
|
||||
```{rust}
|
||||
fn print_number(x: i32) {
|
||||
println!("x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Here's a complete program that uses `print_number`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
print_number(5);
|
||||
}
|
||||
|
||||
fn print_number(x: i32) {
|
||||
println!("x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, function arguments work very similar to `let` declarations:
|
||||
you add a type to the argument name, after a colon.
|
||||
|
||||
Here's a complete program that adds two numbers together and prints them:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
print_sum(5, 6);
|
||||
}
|
||||
|
||||
fn print_sum(x: i32, y: i32) {
|
||||
println!("sum is: {}", x + y);
|
||||
}
|
||||
```
|
||||
|
||||
You separate arguments with a comma, both when you call the function, as well
|
||||
as when you declare it.
|
||||
|
||||
Unlike `let`, you _must_ declare the types of function arguments. This does
|
||||
not work:
|
||||
|
||||
```{ignore}
|
||||
fn print_number(x, y) {
|
||||
println!("x is: {}", x + y);
|
||||
}
|
||||
```
|
||||
|
||||
You get this error:
|
||||
|
||||
```text
|
||||
hello.rs:5:18: 5:19 error: expected `:` but found `,`
|
||||
hello.rs:5 fn print_number(x, y) {
|
||||
```
|
||||
|
||||
This is a deliberate design decision. While full-program inference is possible,
|
||||
languages which have it, like Haskell, often suggest that documenting your
|
||||
types explicitly is a best-practice. We agree that forcing functions to declare
|
||||
types while allowing for inference inside of function bodies is a wonderful
|
||||
sweet spot between full inference and no inference.
|
||||
|
||||
What about returning a value? Here's a function that adds one to an integer:
|
||||
|
||||
```{rust}
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Rust functions return exactly one value, and you declare the type after an
|
||||
'arrow', which is a dash (`-`) followed by a greater-than sign (`>`).
|
||||
|
||||
You'll note the lack of a semicolon here. If we added it in:
|
||||
|
||||
```{ignore}
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
We would get an error:
|
||||
|
||||
```text
|
||||
error: not all control paths return a value
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1;
|
||||
}
|
||||
|
||||
help: consider removing this semicolon:
|
||||
x + 1;
|
||||
^
|
||||
```
|
||||
|
||||
Remember our earlier discussions about semicolons and `()`? Our function claims
|
||||
to return an `i32`, but with a semicolon, it would return `()` instead. Rust
|
||||
realizes this probably isn't what we want, and suggests removing the semicolon.
|
||||
|
||||
This is very much like our `if` statement before: the result of the block
|
||||
(`{}`) is the value of the expression. Other expression-oriented languages,
|
||||
such as Ruby, work like this, but it's a bit unusual in the systems programming
|
||||
world. When people first learn about this, they usually assume that it
|
||||
introduces bugs. But because Rust's type system is so strong, and because unit
|
||||
is its own unique type, we have never seen an issue where adding or removing a
|
||||
semicolon in a return position would cause a bug.
|
||||
|
||||
But what about early returns? Rust does have a keyword for that, `return`:
|
||||
|
||||
```{rust}
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 { return x; }
|
||||
|
||||
x + 1
|
||||
}
|
||||
```
|
||||
|
||||
Using a `return` as the last line of a function works, but is considered poor
|
||||
style:
|
||||
|
||||
```{rust}
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 { return x; }
|
||||
|
||||
return x + 1;
|
||||
}
|
||||
```
|
||||
|
||||
There are some additional ways to define functions, but they involve features
|
||||
that we haven't learned about yet, so let's just leave it at that for now.
|
177
src/doc/trpl/generics.md
Normal file
177
src/doc/trpl/generics.md
Normal file
@ -0,0 +1,177 @@
|
||||
% Generics
|
||||
|
||||
Sometimes, when writing a function or data type, we may want it to work for
|
||||
multiple types of arguments. For example, remember our `OptionalInt` type?
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(int),
|
||||
Missing,
|
||||
}
|
||||
```
|
||||
|
||||
If we wanted to also have an `OptionalFloat64`, we would need a new enum:
|
||||
|
||||
```{rust}
|
||||
enum OptionalFloat64 {
|
||||
Valuef64(f64),
|
||||
Missingf64,
|
||||
}
|
||||
```
|
||||
|
||||
This is really unfortunate. Luckily, Rust has a feature that gives us a better
|
||||
way: generics. Generics are called **parametric polymorphism** in type theory,
|
||||
which means that they are types or functions that have multiple forms ("poly"
|
||||
is multiple, "morph" is form) over a given parameter ("parametric").
|
||||
|
||||
Anyway, enough with type theory declarations, let's check out the generic form
|
||||
of `OptionalInt`. It is actually provided by Rust itself, and looks like this:
|
||||
|
||||
```rust
|
||||
enum Option<T> {
|
||||
Some(T),
|
||||
None,
|
||||
}
|
||||
```
|
||||
|
||||
The `<T>` part, which you've seen a few times before, indicates that this is
|
||||
a generic data type. Inside the declaration of our enum, wherever we see a `T`,
|
||||
we substitute that type for the same type used in the generic. Here's an
|
||||
example of using `Option<T>`, with some extra type annotations:
|
||||
|
||||
```{rust}
|
||||
let x: Option<int> = Some(5i);
|
||||
```
|
||||
|
||||
In the type declaration, we say `Option<int>`. Note how similar this looks to
|
||||
`Option<T>`. So, in this particular `Option`, `T` has the value of `int`. On
|
||||
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5i`.
|
||||
Since that's an `int`, the two sides match, and Rust is happy. If they didn't
|
||||
match, we'd get an error:
|
||||
|
||||
```{rust,ignore}
|
||||
let x: Option<f64> = Some(5i);
|
||||
// error: mismatched types: expected `core::option::Option<f64>`
|
||||
// but found `core::option::Option<int>` (expected f64 but found int)
|
||||
```
|
||||
|
||||
That doesn't mean we can't make `Option<T>`s that hold an `f64`! They just have to
|
||||
match up:
|
||||
|
||||
```{rust}
|
||||
let x: Option<int> = Some(5i);
|
||||
let y: Option<f64> = Some(5.0f64);
|
||||
```
|
||||
|
||||
This is just fine. One definition, multiple uses.
|
||||
|
||||
Generics don't have to only be generic over one type. Consider Rust's built-in
|
||||
`Result<T, E>` type:
|
||||
|
||||
```{rust}
|
||||
enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
}
|
||||
```
|
||||
|
||||
This type is generic over _two_ types: `T` and `E`. By the way, the capital letters
|
||||
can be any letter you'd like. We could define `Result<T, E>` as:
|
||||
|
||||
```{rust}
|
||||
enum Result<H, N> {
|
||||
Ok(H),
|
||||
Err(N),
|
||||
}
|
||||
```
|
||||
|
||||
if we wanted to. Convention says that the first generic parameter should be
|
||||
`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
|
||||
|
||||
The `Result<T, E>` type is intended to
|
||||
be used to return the result of a computation, and to have the ability to
|
||||
return an error if it didn't work out. Here's an example:
|
||||
|
||||
```{rust}
|
||||
let x: Result<f64, String> = Ok(2.3f64);
|
||||
let y: Result<f64, String> = Err("There was an error.".to_string());
|
||||
```
|
||||
|
||||
This particular Result will return an `f64` if there's a success, and a
|
||||
`String` if there's a failure. Let's write a function that uses `Result<T, E>`:
|
||||
|
||||
```{rust}
|
||||
fn inverse(x: f64) -> Result<f64, String> {
|
||||
if x == 0.0f64 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0f64 / x)
|
||||
}
|
||||
```
|
||||
|
||||
We don't want to take the inverse of zero, so we check to make sure that we
|
||||
weren't passed zero. If we were, then we return an `Err`, with a message. If
|
||||
it's okay, we return an `Ok`, with the answer.
|
||||
|
||||
Why does this matter? Well, remember how `match` does exhaustive matches?
|
||||
Here's how this function gets used:
|
||||
|
||||
```{rust}
|
||||
# fn inverse(x: f64) -> Result<f64, String> {
|
||||
# if x == 0.0f64 { return Err("x cannot be zero!".to_string()); }
|
||||
# Ok(1.0f64 / x)
|
||||
# }
|
||||
let x = inverse(25.0f64);
|
||||
|
||||
match x {
|
||||
Ok(x) => println!("The inverse of 25 is {}", x),
|
||||
Err(msg) => println!("Error: {}", msg),
|
||||
}
|
||||
```
|
||||
|
||||
The `match` enforces that we handle the `Err` case. In addition, because the
|
||||
answer is wrapped up in an `Ok`, we can't just use the result without doing
|
||||
the match:
|
||||
|
||||
```{rust,ignore}
|
||||
let x = inverse(25.0f64);
|
||||
println!("{}", x + 2.0f64); // error: binary operation `+` cannot be applied
|
||||
// to type `core::result::Result<f64,collections::string::String>`
|
||||
```
|
||||
|
||||
This function is great, but there's one other problem: it only works for 64 bit
|
||||
floating point values. What if we wanted to handle 32 bit floating point as
|
||||
well? We'd have to write this:
|
||||
|
||||
```{rust}
|
||||
fn inverse32(x: f32) -> Result<f32, String> {
|
||||
if x == 0.0f32 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0f32 / x)
|
||||
}
|
||||
```
|
||||
|
||||
Bummer. What we need is a **generic function**. Luckily, we can write one!
|
||||
However, it won't _quite_ work yet. Before we get into that, let's talk syntax.
|
||||
A generic version of `inverse` would look something like this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn inverse<T>(x: T) -> Result<T, String> {
|
||||
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0 / x)
|
||||
}
|
||||
```
|
||||
|
||||
Just like how we had `Option<T>`, we use a similar syntax for `inverse<T>`.
|
||||
We can then use `T` inside the rest of the signature: `x` has type `T`, and half
|
||||
of the `Result` has type `T`. However, if we try to compile that example, we'll get
|
||||
an error:
|
||||
|
||||
```text
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
Because `T` can be _any_ type, it may be a type that doesn't implement `==`,
|
||||
and therefore, the first line would be wrong. What do we do?
|
||||
|
||||
To fix this example, we need to learn about another Rust feature: traits.
|
891
src/doc/trpl/guessing-game.md
Normal file
891
src/doc/trpl/guessing-game.md
Normal file
@ -0,0 +1,891 @@
|
||||
% Guessing Game
|
||||
|
||||
Okay! We've got the basics of Rust down. Let's write a bigger program.
|
||||
|
||||
For our first project, we'll implement a classic beginner programming problem:
|
||||
the guessing game. Here's how it works: Our program will generate a random
|
||||
integer between one and a hundred. It will then prompt us to enter a guess.
|
||||
Upon entering our guess, it will tell us if we're too low or too high. Once we
|
||||
guess correctly, it will congratulate us. Sound good?
|
||||
|
||||
## Set up
|
||||
|
||||
Let's set up a new project. Go to your projects directory. Remember how we
|
||||
had to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
|
||||
has a command that does that for us. Let's give it a shot:
|
||||
|
||||
```{bash}
|
||||
$ cd ~/projects
|
||||
$ cargo new guessing_game --bin
|
||||
$ cd guessing_game
|
||||
```
|
||||
|
||||
We pass the name of our project to `cargo new`, and then the `--bin` flag,
|
||||
since we're making a binary, rather than a library.
|
||||
|
||||
Check out the generated `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
|
||||
name = "guessing_game"
|
||||
version = "0.0.1"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
Cargo gets this information from your environment. If it's not correct, go ahead
|
||||
and fix that.
|
||||
|
||||
Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
println!("Hello, world!")
|
||||
}
|
||||
```
|
||||
|
||||
Let's try compiling what Cargo gave us:
|
||||
|
||||
```{bash}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
```
|
||||
|
||||
Excellent! Open up your `src/main.rs` again. We'll be writing all of
|
||||
our code in this file. We'll talk about multiple-file projects later on in the
|
||||
guide.
|
||||
|
||||
Before we move on, let me show you one more Cargo command: `run`. `cargo run`
|
||||
is kind of like `cargo build`, but it also then runs the produced executable.
|
||||
Try it out:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Great! The `run` command comes in handy when you need to rapidly iterate on a project.
|
||||
Our game is just such a project, we need to quickly test each iteration before moving on to the next one.
|
||||
|
||||
## Processing a Guess
|
||||
|
||||
Let's get to it! The first thing we need to do for our guessing game is
|
||||
allow our player to input a guess. Put this in your `src/main.rs`:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
}
|
||||
```
|
||||
|
||||
You've seen this code before, when we talked about standard input. We
|
||||
import the `std::io` module with `use`, and then our `main` function contains
|
||||
our program's logic. We print a little message announcing the game, ask the
|
||||
user to input a guess, get their input, and then print it out.
|
||||
|
||||
Because we talked about this in the section on standard I/O, I won't go into
|
||||
more details here. If you need a refresher, go re-read that section.
|
||||
|
||||
## Generating a secret number
|
||||
|
||||
Next, we need to generate a secret number. To do that, we need to use Rust's
|
||||
random number generation, which we haven't talked about yet. Rust includes a
|
||||
bunch of interesting functions in its standard library. If you need a bit of
|
||||
code, it's possible that it's already been written for you! In this case,
|
||||
we do know that Rust has random number generation, but we don't know how to
|
||||
use it.
|
||||
|
||||
Enter the docs. Rust has a page specifically to document the standard library.
|
||||
You can find that page [here](../std/index.html). There's a lot of information on
|
||||
that page, but the best part is the search bar. Right up at the top, there's
|
||||
a box that you can enter in a search term. The search is pretty primitive
|
||||
right now, but is getting better all the time. If you type 'random' in that
|
||||
box, the page will update to [this one](../std/index.html?search=random). The very
|
||||
first result is a link to [`std::rand::random`](../std/rand/fn.random.html). If we
|
||||
click on that result, we'll be taken to its documentation page.
|
||||
|
||||
This page shows us a few things: the type signature of the function, some
|
||||
explanatory text, and then an example. Let's try to modify our code to add in the
|
||||
`random` function and see what happens:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random() % 100) + 1; // secret_number: i32
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
}
|
||||
```
|
||||
|
||||
The first thing we changed was to `use std::rand`, as the docs
|
||||
explained. We then added in a `let` expression to create a variable binding
|
||||
named `secret_number`, and we printed out its result.
|
||||
|
||||
Also, you may wonder why we are using `%` on the result of `rand::random()`.
|
||||
This operator is called 'modulo', and it returns the remainder of a division.
|
||||
By taking the modulo of the result of `rand::random()`, we're limiting the
|
||||
values to be between 0 and 99. Then, we add one to the result, making it from 1
|
||||
to 100. Using modulo can give you a very, very small bias in the result, but
|
||||
for this example, it is not important.
|
||||
|
||||
Let's try to compile this using `cargo build`:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
|
||||
src/main.rs:7 let secret_number = (rand::random() % 100) + 1;
|
||||
^~~~~~~~
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
It didn't work! Rust says "the type of this value must be known in this
|
||||
context." What's up with that? Well, as it turns out, `rand::random()` can
|
||||
generate many kinds of random values, not just integers. And in this case, Rust
|
||||
isn't sure what kind of value `random()` should generate. So we have to help
|
||||
it. With number literals, we can just add an `i32` onto the end to tell Rust they're
|
||||
integers, but that does not work with functions. There's a different syntax,
|
||||
and it looks like this:
|
||||
|
||||
```{rust,ignore}
|
||||
rand::random::<i32>();
|
||||
```
|
||||
|
||||
This says "please give me a random `i32` value." We can change our code to use
|
||||
this hint:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<i32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
}
|
||||
```
|
||||
|
||||
Try running our new program a few times:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 7
|
||||
Please input your guess.
|
||||
4
|
||||
You guessed: 4
|
||||
$ ./target/guessing_game
|
||||
Guess the number!
|
||||
The secret number is: 83
|
||||
Please input your guess.
|
||||
5
|
||||
You guessed: 5
|
||||
$ ./target/guessing_game
|
||||
Guess the number!
|
||||
The secret number is: -29
|
||||
Please input your guess.
|
||||
42
|
||||
You guessed: 42
|
||||
```
|
||||
|
||||
Wait. Negative 29? We wanted a number between one and a hundred! We have two
|
||||
options here: we can either ask `random()` to generate an unsigned integer, which
|
||||
can only be positive, or we can use the `abs()` function. Let's go with the
|
||||
unsigned integer approach. If we want a random positive number, we should ask for
|
||||
a random positive number. Our code looks like this now:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
}
|
||||
```
|
||||
|
||||
And trying it out:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 57
|
||||
Please input your guess.
|
||||
3
|
||||
You guessed: 3
|
||||
```
|
||||
|
||||
Great! Next up: let's compare our guess to the secret guess.
|
||||
|
||||
## Comparing guesses
|
||||
|
||||
If you remember, earlier in the guide, we made a `cmp` function that compared
|
||||
two numbers. Let's add that in, along with a `match` statement to compare our
|
||||
guess to the secret number:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
|
||||
match cmp(input, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
If we try to compile, we'll get some errors:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~
|
||||
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~~~~~~~~~
|
||||
error: aborting due to 2 previous errors
|
||||
```
|
||||
|
||||
This often happens when writing Rust programs, and is one of Rust's greatest
|
||||
strengths. You try out some code, see if it compiles, and Rust tells you that
|
||||
you've done something wrong. In this case, our `cmp` function works on integers,
|
||||
but we've given it unsigned integers. In this case, the fix is easy, because
|
||||
we wrote the `cmp` function! Let's change it to take `uint`s:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
|
||||
|
||||
println!("You guessed: {}", input);
|
||||
|
||||
match cmp(input, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
And try compiling again:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
This error is similar to the last one: we expected to get a `uint`, but we got
|
||||
a `String` instead! That's because our `input` variable is coming from the
|
||||
standard input, and you can guess anything. Try it:
|
||||
|
||||
```bash
|
||||
$ ./target/guessing_game
|
||||
Guess the number!
|
||||
The secret number is: 73
|
||||
Please input your guess.
|
||||
hello
|
||||
You guessed: hello
|
||||
```
|
||||
|
||||
Oops! Also, you'll note that we just ran our program even though it didn't compile.
|
||||
This works because the older version we did successfully compile was still lying
|
||||
around. Gotta be careful!
|
||||
|
||||
Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
|
||||
a function for that:
|
||||
|
||||
```{rust,ignore}
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
```
|
||||
|
||||
The `parse` function takes in a `&str` value and converts it into something.
|
||||
We tell it what kind of something with a type hint. Remember our type hint with
|
||||
`random()`? It looked like this:
|
||||
|
||||
```{rust,ignore}
|
||||
rand::random::<uint>();
|
||||
```
|
||||
|
||||
There's an alternate way of providing a hint too, and that's declaring the type
|
||||
in a `let`:
|
||||
|
||||
```{rust,ignore}
|
||||
let x: uint = rand::random();
|
||||
```
|
||||
|
||||
In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
|
||||
tell `random()` what to generate. In a similar fashion, both of these work:
|
||||
|
||||
```{rust,ignore}
|
||||
let input_num = "5".parse::<uint>(); // input_num: Option<uint>
|
||||
let input_num: Option<uint> = "5".parse(); // input_num: Option<uint>
|
||||
```
|
||||
|
||||
Anyway, with us now converting our input to a number, our code looks like this:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
|
||||
println!("You guessed: {}", input_num);
|
||||
|
||||
match cmp(input_num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
Let's try it out!
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
|
||||
src/main.rs:22 match cmp(input_num, secret_number) {
|
||||
^~~~~~~~~
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
|
||||
need to unwrap the Option. If you remember from before, `match` is a great way
|
||||
to do that. Try this code:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
We use a `match` to either give us the `uint` inside of the `Option`, or else
|
||||
print an error message and return. Let's give this a shot:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 17
|
||||
Please input your guess.
|
||||
5
|
||||
Please input a number!
|
||||
```
|
||||
|
||||
Uh, what? But we did!
|
||||
|
||||
... actually, we didn't. See, when you get a line of input from `stdin()`,
|
||||
you get all the input. Including the `\n` character from you pressing Enter.
|
||||
Therefore, `parse()` sees the string `"5\n"` and says "nope, that's not a
|
||||
number; there's non-number stuff in there!" Luckily for us, `&str`s have an easy
|
||||
method we can use defined on them: `trim()`. One small modification, and our
|
||||
code looks like this:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
Let's try it!
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 58
|
||||
Please input your guess.
|
||||
76
|
||||
You guessed: 76
|
||||
Too big!
|
||||
```
|
||||
|
||||
Nice! You can see I even added spaces before my guess, and it still figured
|
||||
out that I guessed 76. Run the program a few times, and verify that guessing
|
||||
the number works, as well as guessing a number too small.
|
||||
|
||||
The Rust compiler helped us out quite a bit there! This technique is called
|
||||
"lean on the compiler", and it's often useful when working on some code. Let
|
||||
the error messages help guide you towards the correct types.
|
||||
|
||||
Now we've got most of the game working, but we can only make one guess. Let's
|
||||
change that by adding loops!
|
||||
|
||||
## Looping
|
||||
|
||||
As we already discussed, the `loop` keyword gives us an infinite loop.
|
||||
Let's add that in:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
loop {
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => println!("You win!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
|
||||
that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 59
|
||||
Please input your guess.
|
||||
45
|
||||
You guessed: 45
|
||||
Too small!
|
||||
Please input your guess.
|
||||
60
|
||||
You guessed: 60
|
||||
Too big!
|
||||
Please input your guess.
|
||||
59
|
||||
You guessed: 59
|
||||
You win!
|
||||
Please input your guess.
|
||||
quit
|
||||
Please input a number!
|
||||
```
|
||||
|
||||
Ha! `quit` actually quits. As does any other non-number input. Well, this is
|
||||
suboptimal to say the least. First, let's actually quit when you win the game:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
loop {
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => {
|
||||
println!("You win!");
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
By adding the `return` line after the `You win!`, we'll exit the program when
|
||||
we win. We have just one more tweak to make: when someone inputs a non-number,
|
||||
we don't want to quit, we just want to ignore it. Change that `return` to
|
||||
`continue`:
|
||||
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
loop {
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => {
|
||||
println!("You win!");
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
Now we should be good! Let's try:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 61
|
||||
Please input your guess.
|
||||
10
|
||||
You guessed: 10
|
||||
Too small!
|
||||
Please input your guess.
|
||||
99
|
||||
You guessed: 99
|
||||
Too big!
|
||||
Please input your guess.
|
||||
foo
|
||||
Please input a number!
|
||||
Please input your guess.
|
||||
61
|
||||
You guessed: 61
|
||||
You win!
|
||||
```
|
||||
|
||||
Awesome! With one tiny last tweak, we have finished the guessing game. Can you
|
||||
think of what it is? That's right, we don't want to print out the secret number.
|
||||
It was good for testing, but it kind of ruins the game. Here's our final source:
|
||||
|
||||
```{rust,no_run}
|
||||
use std::io;
|
||||
use std::rand;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
|
||||
loop {
|
||||
|
||||
println!("Please input your guess.");
|
||||
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
None => {
|
||||
println!("Please input a number!");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
println!("You guessed: {}", num);
|
||||
|
||||
match cmp(num, secret_number) {
|
||||
Ordering::Less => println!("Too small!"),
|
||||
Ordering::Greater => println!("Too big!"),
|
||||
Ordering::Equal => {
|
||||
println!("You win!");
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
## Complete!
|
||||
|
||||
At this point, you have successfully built the Guessing Game! Congratulations!
|
||||
|
||||
You've now learned the basic syntax of Rust. All of this is relatively close to
|
||||
various other programming languages you have used in the past. These
|
||||
fundamental syntactical and semantic elements will form the foundation for the
|
||||
rest of your Rust education.
|
||||
|
||||
Now that you're an expert at the basics, it's time to learn about some of
|
||||
Rust's more unique features.
|
108
src/doc/trpl/hello-cargo.md
Normal file
108
src/doc/trpl/hello-cargo.md
Normal file
@ -0,0 +1,108 @@
|
||||
% Hello, Cargo!
|
||||
|
||||
[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their
|
||||
Rust projects. Cargo is currently in an alpha state, just like Rust, and so it
|
||||
is still a work in progress. However, it is already good enough to use for many
|
||||
Rust projects, and so it is assumed that Rust projects will use Cargo from the
|
||||
beginning.
|
||||
|
||||
Cargo manages three things: building your code, downloading the dependencies
|
||||
your code needs, and building the dependencies your code needs. At first, your
|
||||
program doesn't have any dependencies, so we'll only be using the first part of
|
||||
its functionality. Eventually, we'll add more. Since we started off by using
|
||||
Cargo, it'll be easy to add later.
|
||||
|
||||
If you installed Rust via the official installers you will also have
|
||||
Cargo. If you installed Rust some other way, you may want to [check
|
||||
the Cargo
|
||||
README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies)
|
||||
for specific instructions about installing it.
|
||||
|
||||
Let's convert Hello World to Cargo.
|
||||
|
||||
To Cargo-ify our project, we need to do two things: Make a `Cargo.toml`
|
||||
configuration file, and put our source file in the right place. Let's
|
||||
do that part first:
|
||||
|
||||
```{bash}
|
||||
$ mkdir src
|
||||
$ mv main.rs src/main.rs
|
||||
```
|
||||
|
||||
Cargo expects your source files to live inside a `src` directory. That leaves
|
||||
the top level for other things, like READMEs, license information, and anything
|
||||
not related to your code. Cargo helps us keep our projects nice and tidy. A
|
||||
place for everything, and everything in its place.
|
||||
|
||||
Next, our configuration file:
|
||||
|
||||
```{bash}
|
||||
$ editor Cargo.toml
|
||||
```
|
||||
|
||||
Make sure to get this name right: you need the capital `C`!
|
||||
|
||||
Put this inside:
|
||||
|
||||
```toml
|
||||
[package]
|
||||
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
authors = [ "Your name <you@example.com>" ]
|
||||
|
||||
[[bin]]
|
||||
|
||||
name = "hello_world"
|
||||
```
|
||||
|
||||
This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let
|
||||
it explain itself to you:
|
||||
|
||||
> TOML aims to be a minimal configuration file format that's easy to read due
|
||||
> to obvious semantics. TOML is designed to map unambiguously to a hash table.
|
||||
> TOML should be easy to parse into data structures in a wide variety of
|
||||
> languages.
|
||||
|
||||
TOML is very similar to INI, but with some extra goodies.
|
||||
|
||||
Anyway, there are two **table**s in this file: `package` and `bin`. The first
|
||||
tells Cargo metadata about your package. The second tells Cargo that we're
|
||||
interested in building a binary, not a library (though we could do both!), as
|
||||
well as what it is named.
|
||||
|
||||
Once you have this file in place, we should be ready to build! Try this:
|
||||
|
||||
```{bash}
|
||||
$ cargo build
|
||||
Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world)
|
||||
$ ./target/hello_world
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Bam! We build our project with `cargo build`, and run it with
|
||||
`./target/hello_world`. This hasn't bought us a whole lot over our simple use
|
||||
of `rustc`, but think about the future: when our project has more than one
|
||||
file, we would need to call `rustc` more than once, and pass it a bunch of options to
|
||||
tell it to build everything together. With Cargo, as our project grows, we can
|
||||
just `cargo build` and it'll work the right way.
|
||||
|
||||
You'll also notice that Cargo has created a new file: `Cargo.lock`.
|
||||
|
||||
```toml
|
||||
[root]
|
||||
name = "hello_world"
|
||||
version = "0.0.1"
|
||||
```
|
||||
|
||||
This file is used by Cargo to keep track of dependencies in your application.
|
||||
Right now, we don't have any, so it's a bit sparse. You won't ever need
|
||||
to touch this file yourself, just let Cargo handle it.
|
||||
|
||||
That's it! We've successfully built `hello_world` with Cargo. Even though our
|
||||
program is simple, it's using much of the real tooling that you'll use for the
|
||||
rest of your Rust career.
|
||||
|
||||
Now that you've got the tools down, let's actually learn more about the Rust
|
||||
language itself. These are the basics that will serve you well through the rest
|
||||
of your time with Rust.
|
164
src/doc/trpl/hello-world.md
Normal file
164
src/doc/trpl/hello-world.md
Normal file
@ -0,0 +1,164 @@
|
||||
% Hello, world!
|
||||
|
||||
Now that you have Rust installed, let's write your first Rust program. It's
|
||||
traditional to make your first program in any new language one that prints the
|
||||
text "Hello, world!" to the screen. The nice thing about starting with such a
|
||||
simple program is that you can verify that your compiler isn't just installed,
|
||||
but also working properly. And printing information to the screen is a pretty
|
||||
common thing to do.
|
||||
|
||||
The first thing that we need to do is make a file to put our code in. I like
|
||||
to make a `projects` directory in my home directory, and keep all my projects
|
||||
there. Rust does not care where your code lives.
|
||||
|
||||
This actually leads to one other concern we should address: this guide will
|
||||
assume that you have basic familiarity with the command line. Rust does not
|
||||
require that you know a whole ton about the command line, but until the
|
||||
language is in a more finished state, IDE support is spotty. Rust makes no
|
||||
specific demands on your editing tooling, or where your code lives.
|
||||
|
||||
With that said, let's make a directory in our projects directory.
|
||||
|
||||
```{bash}
|
||||
$ mkdir ~/projects
|
||||
$ cd ~/projects
|
||||
$ mkdir hello_world
|
||||
$ cd hello_world
|
||||
```
|
||||
|
||||
If you're on Windows and not using PowerShell, the `~` may not work. Consult
|
||||
the documentation for your shell for more details.
|
||||
|
||||
Let's make a new source file next. I'm going to use the syntax `editor
|
||||
filename` to represent editing a file in these examples, but you should use
|
||||
whatever method you want. We'll call our file `main.rs`:
|
||||
|
||||
```{bash}
|
||||
$ editor main.rs
|
||||
```
|
||||
|
||||
Rust files always end in a `.rs` extension. If you're using more than one word
|
||||
in your filename, use an underscore. `hello_world.rs` rather than
|
||||
`helloworld.rs`.
|
||||
|
||||
Now that you've got your file open, type this in:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
Save the file, and then type this into your terminal window:
|
||||
|
||||
```{bash}
|
||||
$ rustc main.rs
|
||||
$ ./main # or main.exe on Windows
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code.
|
||||
|
||||
Success! Let's go over what just happened in detail.
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
These lines define a **function** in Rust. The `main` function is special:
|
||||
it's the beginning of every Rust program. The first line says "I'm declaring a
|
||||
function named `main`, which takes no arguments and returns nothing." If there
|
||||
were arguments, they would go inside the parentheses (`(` and `)`), and because
|
||||
we aren't returning anything from this function, we've dropped that notation
|
||||
entirely. We'll get to it later.
|
||||
|
||||
You'll also note that the function is wrapped in curly braces (`{` and `}`).
|
||||
Rust requires these around all function bodies. It is also considered good
|
||||
style to put the opening curly brace on the same line as the function
|
||||
declaration, with one space in between.
|
||||
|
||||
Next up is this line:
|
||||
|
||||
```{rust}
|
||||
println!("Hello, world!");
|
||||
```
|
||||
|
||||
This line does all of the work in our little program. There are a number of
|
||||
details that are important here. The first is that it's indented with four
|
||||
spaces, not tabs. Please configure your editor of choice to insert four spaces
|
||||
with the tab key. We provide some [sample configurations for various
|
||||
editors](https://github.com/rust-lang/rust/tree/master/src/etc).
|
||||
|
||||
The second point is the `println!()` part. This is calling a Rust **macro**,
|
||||
which is how metaprogramming is done in Rust. If it were a function instead, it
|
||||
would look like this: `println()`. For our purposes, we don't need to worry
|
||||
about this difference. Just know that sometimes, you'll see a `!`, and that
|
||||
means that you're calling a macro instead of a normal function. Rust implements
|
||||
`println!` as a macro rather than a function for good reasons, but that's a
|
||||
very advanced topic. You'll learn more when we talk about macros later. One
|
||||
last thing to mention: Rust's macros are significantly different from C macros,
|
||||
if you've used those. Don't be scared of using macros. We'll get to the details
|
||||
eventually, you'll just have to trust us for now.
|
||||
|
||||
Next, `"Hello, world!"` is a **string**. Strings are a surprisingly complicated
|
||||
topic in a systems programming language, and this is a **statically allocated**
|
||||
string. We will talk more about different kinds of allocation later. We pass
|
||||
this string as an argument to `println!`, which prints the string to the
|
||||
screen. Easy enough!
|
||||
|
||||
Finally, the line ends with a semicolon (`;`). Rust is an **expression
|
||||
oriented** language, which means that most things are expressions. The `;` is
|
||||
used to indicate that this expression is over, and the next one is ready to
|
||||
begin. Most lines of Rust code end with a `;`. We will cover this in-depth
|
||||
later in the guide.
|
||||
|
||||
Finally, actually **compiling** and **running** our program. We can compile
|
||||
with our compiler, `rustc`, by passing it the name of our source file:
|
||||
|
||||
```{bash}
|
||||
$ rustc main.rs
|
||||
```
|
||||
|
||||
This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust
|
||||
will output a binary executable. You can see it with `ls`:
|
||||
|
||||
```{bash}
|
||||
$ ls
|
||||
main main.rs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
|
||||
```{bash}
|
||||
$ dir
|
||||
main.exe main.rs
|
||||
```
|
||||
|
||||
There are now two files: our source code, with the `.rs` extension, and the
|
||||
executable (`main.exe` on Windows, `main` everywhere else)
|
||||
|
||||
```{bash}
|
||||
$ ./main # or main.exe on Windows
|
||||
```
|
||||
|
||||
This prints out our `Hello, world!` text to our terminal.
|
||||
|
||||
If you come from a dynamically typed language like Ruby, Python, or JavaScript,
|
||||
you may not be used to these two steps being separate. Rust is an
|
||||
**ahead-of-time compiled language**, which means that you can compile a
|
||||
program, give it to someone else, and they don't need to have Rust installed.
|
||||
If you give someone a `.rb` or `.py` or `.js` file, they need to have
|
||||
Ruby/Python/JavaScript installed, but you just need one command to both compile
|
||||
and run your program. Everything is a tradeoff in language design, and Rust has
|
||||
made its choice.
|
||||
|
||||
Congratulations! You have officially written a Rust program. That makes you a
|
||||
Rust programmer! Welcome.
|
||||
|
||||
Next, I'd like to introduce you to another tool, Cargo, which is used to write
|
||||
real-world Rust programs. Just using `rustc` is nice for simple things, but as
|
||||
your project grows, you'll want something to help you manage all of the options
|
||||
that it has, and to make it easy to share your code with other people and
|
||||
projects.
|
141
src/doc/trpl/if.md
Normal file
141
src/doc/trpl/if.md
Normal file
@ -0,0 +1,141 @@
|
||||
% `if`
|
||||
|
||||
Rust's take on `if` is not particularly complex, but it's much more like the
|
||||
`if` you'll find in a dynamically typed language than in a more traditional
|
||||
systems language. So let's talk about it, to make sure you grasp the nuances.
|
||||
|
||||
`if` is a specific form of a more general concept, the 'branch.' The name comes
|
||||
from a branch in a tree: a decision point, where depending on a choice,
|
||||
multiple paths can be taken.
|
||||
|
||||
In the case of `if`, there is one choice that leads down two paths:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
if x == 5 {
|
||||
println!("x is five!");
|
||||
}
|
||||
```
|
||||
|
||||
If we changed the value of `x` to something else, this line would not print.
|
||||
More specifically, if the expression after the `if` evaluates to `true`, then
|
||||
the block is executed. If it's `false`, then it is not.
|
||||
|
||||
If you want something to happen in the `false` case, use an `else`:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
if x == 5 {
|
||||
println!("x is five!");
|
||||
} else {
|
||||
println!("x is not five :(");
|
||||
}
|
||||
```
|
||||
|
||||
This is all pretty standard. However, you can also do this:
|
||||
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
let y = if x == 5 {
|
||||
10
|
||||
} else {
|
||||
15
|
||||
}; // y: i32
|
||||
```
|
||||
|
||||
Which we can (and probably should) write like this:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
let y = if x == 5 { 10 } else { 15 }; // y: i32
|
||||
```
|
||||
|
||||
This reveals two interesting things about Rust: it is an expression-based
|
||||
language, and semicolons are different from semicolons in other 'curly brace
|
||||
and semicolon'-based languages. These two things are related.
|
||||
|
||||
## Expressions vs. Statements
|
||||
|
||||
Rust is primarily an expression based language. There are only two kinds of
|
||||
statements, and everything else is an expression.
|
||||
|
||||
So what's the difference? Expressions return a value, and statements do not.
|
||||
In many languages, `if` is a statement, and therefore, `let x = if ...` would
|
||||
make no sense. But in Rust, `if` is an expression, which means that it returns
|
||||
a value. We can then use this value to initialize the binding.
|
||||
|
||||
Speaking of which, bindings are a kind of the first of Rust's two statements.
|
||||
The proper name is a **declaration statement**. So far, `let` is the only kind
|
||||
of declaration statement we've seen. Let's talk about that some more.
|
||||
|
||||
In some languages, variable bindings can be written as expressions, not just
|
||||
statements. Like Ruby:
|
||||
|
||||
```{ruby}
|
||||
x = y = 5
|
||||
```
|
||||
|
||||
In Rust, however, using `let` to introduce a binding is _not_ an expression. The
|
||||
following will produce a compile-time error:
|
||||
|
||||
```{ignore}
|
||||
let x = (let y = 5); // expected identifier, found keyword `let`
|
||||
```
|
||||
|
||||
The compiler is telling us here that it was expecting to see the beginning of
|
||||
an expression, and a `let` can only begin a statement, not an expression.
|
||||
|
||||
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
|
||||
expression, although its value is not particularly useful. Unlike C, where an
|
||||
assignment evaluates to the assigned value (e.g. `5` in the previous example),
|
||||
in Rust the value of an assignment is the unit type `()` (which we'll cover later).
|
||||
|
||||
The second kind of statement in Rust is the **expression statement**. Its
|
||||
purpose is to turn any expression into a statement. In practical terms, Rust's
|
||||
grammar expects statements to follow other statements. This means that you use
|
||||
semicolons to separate expressions from each other. This means that Rust
|
||||
looks a lot like most other languages that require you to use semicolons
|
||||
at the end of every line, and you will see semicolons at the end of almost
|
||||
every line of Rust code you see.
|
||||
|
||||
What is this exception that makes us say 'almost?' You saw it already, in this
|
||||
code:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
let y: i32 = if x == 5 { 10 } else { 15 };
|
||||
```
|
||||
|
||||
Note that I've added the type annotation to `y`, to specify explicitly that I
|
||||
want `y` to be an integer.
|
||||
|
||||
This is not the same as this, which won't compile:
|
||||
|
||||
```{ignore}
|
||||
let x = 5;
|
||||
|
||||
let y: i32 = if x == 5 { 10; } else { 15; };
|
||||
```
|
||||
|
||||
Note the semicolons after the 10 and 15. Rust will give us the following error:
|
||||
|
||||
```text
|
||||
error: mismatched types: expected `i32` but found `()` (expected i32 but found ())
|
||||
```
|
||||
|
||||
We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
|
||||
special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
|
||||
variable of type `i32`. It's only a valid value for variables of the type `()`,
|
||||
which aren't very useful. Remember how we said statements don't return a value?
|
||||
Well, that's the purpose of unit in this case. The semicolon turns any
|
||||
expression into a statement by throwing away its value and returning unit
|
||||
instead.
|
||||
|
||||
There's one more time in which you won't see a semicolon at the end of a line
|
||||
of Rust code. For that, we'll need our next concept: functions.
|
89
src/doc/trpl/installing-rust.md
Normal file
89
src/doc/trpl/installing-rust.md
Normal file
@ -0,0 +1,89 @@
|
||||
% Installing Rust
|
||||
|
||||
The first step to using Rust is to install it! There are a number of ways to
|
||||
install Rust, but the easiest is to use the `rustup` script. If you're on
|
||||
Linux or a Mac, all you need to do is this (note that you don't need to type
|
||||
in the `$`s, they just indicate the start of each command):
|
||||
|
||||
```bash
|
||||
$ curl -L https://static.rust-lang.org/rustup.sh | sudo sh
|
||||
```
|
||||
|
||||
If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`,
|
||||
please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script:
|
||||
|
||||
```bash
|
||||
$ curl -L https://static.rust-lang.org/rustup.sh -O
|
||||
$ sudo sh rustup.sh
|
||||
```
|
||||
|
||||
If you're on Windows, please download either the [32-bit
|
||||
installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe)
|
||||
or the [64-bit
|
||||
installer](https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe)
|
||||
and run it.
|
||||
|
||||
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
|
||||
Not every programming language is great for everyone. Just pass an argument to
|
||||
the script:
|
||||
|
||||
```bash
|
||||
$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh -s -- --uninstall
|
||||
```
|
||||
|
||||
If you used the Windows installer, just re-run the `.exe` and it will give you
|
||||
an uninstall option.
|
||||
|
||||
You can re-run this script any time you want to update Rust. Which, at this
|
||||
point, is often. Rust is still pre-1.0, and so people assume that you're using
|
||||
a very recent Rust.
|
||||
|
||||
This brings me to one other point: some people, and somewhat rightfully so, get
|
||||
very upset when we tell you to `curl | sudo sh`. And they should be! Basically,
|
||||
when you do this, you are trusting that the good people who maintain Rust
|
||||
aren't going to hack your computer and do bad things. That's a good instinct!
|
||||
If you're one of those people, please check out the documentation on [building
|
||||
Rust from Source](https://github.com/rust-lang/rust#building-from-source), or
|
||||
[the official binary downloads](http://www.rust-lang.org/install.html). And we
|
||||
promise that this method will not be the way to install Rust forever: it's just
|
||||
the easiest way to keep people updated while Rust is in its alpha state.
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
We extensively test Rust on these platforms, and a few others, too, like
|
||||
Android. But these are the ones most likely to work, as they have the most
|
||||
testing.
|
||||
|
||||
Finally, a comment about Windows. Rust considers Windows to be a first-class
|
||||
platform upon release, but if we're honest, the Windows experience isn't as
|
||||
integrated as the Linux/OS X experience is. We're working on it! If anything
|
||||
does not work, it is a bug. Please let us know if that happens. Each and every
|
||||
commit is tested against Windows just like any other platform.
|
||||
|
||||
If you've got Rust installed, you can open up a shell, and type this:
|
||||
|
||||
```bash
|
||||
$ rustc --version
|
||||
```
|
||||
|
||||
You should see some output that looks something like this:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04 20:02:14 +0000)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
|
||||
If not, there are a number of places where you can get help. The easiest is
|
||||
[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which
|
||||
you can access through
|
||||
[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click
|
||||
that link, and you'll be chatting with other Rustaceans (a silly nickname we
|
||||
call ourselves), and we can help you out. Other great resources include [our
|
||||
forum](http://discuss.rust-lang.org/), [the /r/rust
|
||||
subreddit](http://www.reddit.com/r/rust), and [Stack
|
||||
Overflow](http://stackoverflow.com/questions/tagged/rust).
|
7
src/doc/trpl/intermediate.md
Normal file
7
src/doc/trpl/intermediate.md
Normal file
@ -0,0 +1,7 @@
|
||||
% Intermediate
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
339
src/doc/trpl/iterators.md
Normal file
339
src/doc/trpl/iterators.md
Normal file
@ -0,0 +1,339 @@
|
||||
% Iterators
|
||||
|
||||
Let's talk about loops.
|
||||
|
||||
Remember Rust's `for` loop? Here's an example:
|
||||
|
||||
```{rust}
|
||||
for x in range(0i, 10i) {
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Now that you know more Rust, we can talk in detail about how this works. The
|
||||
`range` function returns an **iterator**. An iterator is something that we can
|
||||
call the `.next()` method on repeatedly, and it gives us a sequence of things.
|
||||
|
||||
Like this:
|
||||
|
||||
```{rust}
|
||||
let mut range = range(0i, 10i);
|
||||
|
||||
loop {
|
||||
match range.next() {
|
||||
Some(x) => {
|
||||
println!("{}", x);
|
||||
},
|
||||
None => { break }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We make a mutable binding to the return value of `range`, which is our iterator.
|
||||
We then `loop`, with an inner `match`. This `match` is used on the result of
|
||||
`range.next()`, which gives us a reference to the next value of the iterator.
|
||||
`next` returns an `Option<int>`, in this case, which will be `Some(int)` when
|
||||
we have a value and `None` once we run out. If we get `Some(int)`, we print it
|
||||
out, and if we get `None`, we `break` out of the loop.
|
||||
|
||||
This code sample is basically the same as our `for` loop version. The `for`
|
||||
loop is just a handy way to write this `loop`/`match`/`break` construct.
|
||||
|
||||
`for` loops aren't the only thing that uses iterators, however. Writing your
|
||||
own iterator involves implementing the `Iterator` trait. While doing that is
|
||||
outside of the scope of this guide, Rust provides a number of useful iterators
|
||||
to accomplish various tasks. Before we talk about those, we should talk about a
|
||||
Rust anti-pattern. And that's `range`.
|
||||
|
||||
Yes, we just talked about how `range` is cool. But `range` is also very
|
||||
primitive. For example, if you needed to iterate over the contents of
|
||||
a vector, you may be tempted to write this:
|
||||
|
||||
```{rust}
|
||||
let nums = vec![1i, 2i, 3i];
|
||||
|
||||
for i in range(0u, nums.len()) {
|
||||
println!("{}", nums[i]);
|
||||
}
|
||||
```
|
||||
|
||||
This is strictly worse than using an actual iterator. The `.iter()` method on
|
||||
vectors returns an iterator which iterates through a reference to each element
|
||||
of the vector in turn. So write this:
|
||||
|
||||
```{rust}
|
||||
let nums = vec![1i, 2i, 3i];
|
||||
|
||||
for num in nums.iter() {
|
||||
println!("{}", num);
|
||||
}
|
||||
```
|
||||
|
||||
There are two reasons for this. First, this more directly expresses what we
|
||||
mean. We iterate through the entire vector, rather than iterating through
|
||||
indexes, and then indexing the vector. Second, this version is more efficient:
|
||||
the first version will have extra bounds checking because it used indexing,
|
||||
`nums[i]`. But since we yield a reference to each element of the vector in turn
|
||||
with the iterator, there's no bounds checking in the second example. This is
|
||||
very common with iterators: we can ignore unnecessary bounds checks, but still
|
||||
know that we're safe.
|
||||
|
||||
There's another detail here that's not 100% clear because of how `println!`
|
||||
works. `num` is actually of type `&int`. That is, it's a reference to an `int`,
|
||||
not an `int` itself. `println!` handles the dereferencing for us, so we don't
|
||||
see it. This code works fine too:
|
||||
|
||||
```{rust}
|
||||
let nums = vec![1i, 2i, 3i];
|
||||
|
||||
for num in nums.iter() {
|
||||
println!("{}", *num);
|
||||
}
|
||||
```
|
||||
|
||||
Now we're explicitly dereferencing `num`. Why does `iter()` give us references?
|
||||
Well, if it gave us the data itself, we would have to be its owner, which would
|
||||
involve making a copy of the data and giving us the copy. With references,
|
||||
we're just borrowing a reference to the data, and so it's just passing
|
||||
a reference, without needing to do the copy.
|
||||
|
||||
So, now that we've established that `range` is often not what you want, let's
|
||||
talk about what you do want instead.
|
||||
|
||||
There are three broad classes of things that are relevant here: iterators,
|
||||
**iterator adapters**, and **consumers**. Here's some definitions:
|
||||
|
||||
* 'iterators' give you a sequence of values.
|
||||
* 'iterator adapters' operate on an iterator, producing a new iterator with a
|
||||
different output sequence.
|
||||
* 'consumers' operate on an iterator, producing some final set of values.
|
||||
|
||||
Let's talk about consumers first, since you've already seen an iterator,
|
||||
`range`.
|
||||
|
||||
## Consumers
|
||||
|
||||
A 'consumer' operates on an iterator, returning some kind of value or values.
|
||||
The most common consumer is `collect()`. This code doesn't quite compile,
|
||||
but it shows the intention:
|
||||
|
||||
```{rust,ignore}
|
||||
let one_to_one_hundred = range(1i, 101i).collect();
|
||||
```
|
||||
|
||||
As you can see, we call `collect()` on our iterator. `collect()` takes
|
||||
as many values as the iterator will give it, and returns a collection
|
||||
of the results. So why won't this compile? Rust can't determine what
|
||||
type of things you want to collect, and so you need to let it know.
|
||||
Here's the version that does compile:
|
||||
|
||||
```{rust}
|
||||
let one_to_one_hundred = range(1i, 101i).collect::<Vec<int>>();
|
||||
```
|
||||
|
||||
If you remember, the `::<>` syntax allows us to give a type hint,
|
||||
and so we tell it that we want a vector of integers.
|
||||
|
||||
`collect()` is the most common consumer, but there are others too. `find()`
|
||||
is one:
|
||||
|
||||
```{rust}
|
||||
let greater_than_forty_two = range(0i, 100i)
|
||||
.find(|x| *x > 42);
|
||||
|
||||
match greater_than_forty_two {
|
||||
Some(_) => println!("We got some numbers!"),
|
||||
None => println!("No numbers found :("),
|
||||
}
|
||||
```
|
||||
|
||||
`find` takes a closure, and works on a reference to each element of an
|
||||
iterator. This closure returns `true` if the element is the element we're
|
||||
looking for, and `false` otherwise. Because we might not find a matching
|
||||
element, `find` returns an `Option` rather than the element itself.
|
||||
|
||||
Another important consumer is `fold`. Here's what it looks like:
|
||||
|
||||
```{rust}
|
||||
let sum = range(1i, 4i)
|
||||
.fold(0i, |sum, x| sum + x);
|
||||
```
|
||||
|
||||
`fold()` is a consumer that looks like this:
|
||||
`fold(base, |accumulator, element| ...)`. It takes two arguments: the first
|
||||
is an element called the "base". The second is a closure that itself takes two
|
||||
arguments: the first is called the "accumulator," and the second is an
|
||||
"element." Upon each iteration, the closure is called, and the result is the
|
||||
value of the accumulator on the next iteration. On the first iteration, the
|
||||
base is the value of the accumulator.
|
||||
|
||||
Okay, that's a bit confusing. Let's examine the values of all of these things
|
||||
in this iterator:
|
||||
|
||||
| base | accumulator | element | closure result |
|
||||
|------|-------------|---------|----------------|
|
||||
| 0i | 0i | 1i | 1i |
|
||||
| 0i | 1i | 2i | 3i |
|
||||
| 0i | 3i | 3i | 6i |
|
||||
|
||||
We called `fold()` with these arguments:
|
||||
|
||||
```{rust}
|
||||
# range(1i, 4i)
|
||||
.fold(0i, |sum, x| sum + x);
|
||||
```
|
||||
|
||||
So, `0i` is our base, `sum` is our accumulator, and `x` is our element. On the
|
||||
first iteration, we set `sum` to `0i`, and `x` is the first element of `nums`,
|
||||
`1i`. We then add `sum` and `x`, which gives us `0i + 1i = 1i`. On the second
|
||||
iteration, that value becomes our accumulator, `sum`, and the element is
|
||||
the second element of the array, `2i`. `1i + 2i = 3i`, and so that becomes
|
||||
the value of the accumulator for the last iteration. On that iteration,
|
||||
`x` is the last element, `3i`, and `3i + 3i = 6i`, which is our final
|
||||
result for our sum. `1 + 2 + 3 = 6`, and that's the result we got.
|
||||
|
||||
Whew. `fold` can be a bit strange the first few times you see it, but once it
|
||||
clicks, you can use it all over the place. Any time you have a list of things,
|
||||
and you want a single result, `fold` is appropriate.
|
||||
|
||||
Consumers are important due to one additional property of iterators we haven't
|
||||
talked about yet: laziness. Let's talk some more about iterators, and you'll
|
||||
see why consumers matter.
|
||||
|
||||
## Iterators
|
||||
|
||||
As we've said before, an iterator is something that we can call the
|
||||
`.next()` method on repeatedly, and it gives us a sequence of things.
|
||||
Because you need to call the method, this means that iterators
|
||||
are **lazy** and don't need to generate all of the values upfront.
|
||||
This code, for example, does not actually generate the numbers
|
||||
`1-100`, and just creates a value that represents the sequence:
|
||||
|
||||
```{rust}
|
||||
let nums = range(1i, 100i);
|
||||
```
|
||||
|
||||
Since we didn't do anything with the range, it didn't generate the sequence.
|
||||
Let's add the consumer:
|
||||
|
||||
```{rust}
|
||||
let nums = range(1i, 100i).collect::<Vec<int>>();
|
||||
```
|
||||
|
||||
Now, `collect()` will require that `range()` give it some numbers, and so
|
||||
it will do the work of generating the sequence.
|
||||
|
||||
`range` is one of two basic iterators that you'll see. The other is `iter()`,
|
||||
which you've used before. `iter()` can turn a vector into a simple iterator
|
||||
that gives you each element in turn:
|
||||
|
||||
```{rust}
|
||||
let nums = [1i, 2i, 3i];
|
||||
|
||||
for num in nums.iter() {
|
||||
println!("{}", num);
|
||||
}
|
||||
```
|
||||
|
||||
These two basic iterators should serve you well. There are some more
|
||||
advanced iterators, including ones that are infinite. Like `count`:
|
||||
|
||||
```{rust}
|
||||
std::iter::count(1i, 5i);
|
||||
```
|
||||
|
||||
This iterator counts up from one, adding five each time. It will give
|
||||
you a new integer every time, forever (well, technically, until it reaches the
|
||||
maximum number representable by an `int`). But since iterators are lazy,
|
||||
that's okay! You probably don't want to use `collect()` on it, though...
|
||||
|
||||
That's enough about iterators. Iterator adapters are the last concept
|
||||
we need to talk about with regards to iterators. Let's get to it!
|
||||
|
||||
## Iterator adapters
|
||||
|
||||
"Iterator adapters" take an iterator and modify it somehow, producing
|
||||
a new iterator. The simplest one is called `map`:
|
||||
|
||||
```{rust,ignore}
|
||||
range(1i, 100i).map(|x| x + 1i);
|
||||
```
|
||||
|
||||
`map` is called upon another iterator, and produces a new iterator where each
|
||||
element reference has the closure it's been given as an argument called on it.
|
||||
So this would give us the numbers from `2-100`. Well, almost! If you
|
||||
compile the example, you'll get a warning:
|
||||
|
||||
```{notrust,ignore}
|
||||
warning: unused result which must be used: iterator adaptors are lazy and
|
||||
do nothing unless consumed, #[warn(unused_must_use)] on by default
|
||||
range(1i, 100i).map(|x| x + 1i);
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
Laziness strikes again! That closure will never execute. This example
|
||||
doesn't print any numbers:
|
||||
|
||||
```{rust,ignore}
|
||||
range(1i, 100i).map(|x| println!("{}", x));
|
||||
```
|
||||
|
||||
If you are trying to execute a closure on an iterator for its side effects,
|
||||
just use `for` instead.
|
||||
|
||||
There are tons of interesting iterator adapters. `take(n)` will return an
|
||||
iterator over the next `n` elements of the original iterator, note that this
|
||||
has no side effect on the original iterator. Let's try it out with our infinite
|
||||
iterator from before, `count()`:
|
||||
|
||||
```{rust}
|
||||
for i in std::iter::count(1i, 5i).take(5) {
|
||||
println!("{}", i);
|
||||
}
|
||||
```
|
||||
|
||||
This will print
|
||||
|
||||
```{notrust,ignore}
|
||||
1
|
||||
6
|
||||
11
|
||||
16
|
||||
21
|
||||
```
|
||||
|
||||
`filter()` is an adapter that takes a closure as an argument. This closure
|
||||
returns `true` or `false`. The new iterator `filter()` produces
|
||||
only the elements that that closure returns `true` for:
|
||||
|
||||
```{rust}
|
||||
for i in range(1i, 100i).filter(|&x| x % 2 == 0) {
|
||||
println!("{}", i);
|
||||
}
|
||||
```
|
||||
|
||||
This will print all of the even numbers between one and a hundred.
|
||||
(Note that because `filter` doesn't consume the elements that are
|
||||
being iterated over, it is passed a reference to each element, and
|
||||
thus the filter predicate uses the `&x` pattern to extract the integer
|
||||
itself.)
|
||||
|
||||
You can chain all three things together: start with an iterator, adapt it
|
||||
a few times, and then consume the result. Check it out:
|
||||
|
||||
```{rust}
|
||||
range(1i, 1000i)
|
||||
.filter(|&x| x % 2 == 0)
|
||||
.filter(|&x| x % 3 == 0)
|
||||
.take(5)
|
||||
.collect::<Vec<int>>();
|
||||
```
|
||||
|
||||
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
|
||||
|
||||
This is just a small taste of what iterators, iterator adapters, and consumers
|
||||
can help you with. There are a number of really useful iterators, and you can
|
||||
write your own as well. Iterators provide a safe, efficient way to manipulate
|
||||
all kinds of lists. They're a little unusual at first, but if you play with
|
||||
them, you'll get hooked. For a full list of the different iterators and
|
||||
consumers, check out the [iterator module documentation](../std/iter/index.html).
|
133
src/doc/trpl/looping.md
Normal file
133
src/doc/trpl/looping.md
Normal file
@ -0,0 +1,133 @@
|
||||
% Looping
|
||||
|
||||
Looping is the last basic construct that we haven't learned yet in Rust. Rust has
|
||||
two main looping constructs: `for` and `while`.
|
||||
|
||||
## `for`
|
||||
|
||||
The `for` loop is used to loop a particular number of times. Rust's `for` loops
|
||||
work a bit differently than in other systems languages, however. Rust's `for`
|
||||
loop doesn't look like this "C-style" `for` loop:
|
||||
|
||||
```{c}
|
||||
for (x = 0; x < 10; x++) {
|
||||
printf( "%d\n", x );
|
||||
}
|
||||
```
|
||||
|
||||
Instead, it looks like this:
|
||||
|
||||
```{rust}
|
||||
for x in range(0, 10) {
|
||||
println!("{}", x); // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
In slightly more abstract terms,
|
||||
|
||||
```{ignore}
|
||||
for var in expression {
|
||||
code
|
||||
}
|
||||
```
|
||||
|
||||
The expression is an iterator, which we will discuss in more depth later in the
|
||||
guide. The iterator gives back a series of elements. Each element is one
|
||||
iteration of the loop. That value is then bound to the name `var`, which is
|
||||
valid for the loop body. Once the body is over, the next value is fetched from
|
||||
the iterator, and we loop another time. When there are no more values, the
|
||||
`for` loop is over.
|
||||
|
||||
In our example, `range` is a function that takes a start and an end position,
|
||||
and gives an iterator over those values. The upper bound is exclusive, though,
|
||||
so our loop will print `0` through `9`, not `10`.
|
||||
|
||||
Rust does not have the "C-style" `for` loop on purpose. Manually controlling
|
||||
each element of the loop is complicated and error prone, even for experienced C
|
||||
developers.
|
||||
|
||||
We'll talk more about `for` when we cover **iterator**s, later in the Guide.
|
||||
|
||||
## `while`
|
||||
|
||||
The other kind of looping construct in Rust is the `while` loop. It looks like
|
||||
this:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u; // mut x: uint
|
||||
let mut done = false; // mut done: bool
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
`while` loops are the correct choice when you're not sure how many times
|
||||
you need to loop.
|
||||
|
||||
If you need an infinite loop, you may be tempted to write this:
|
||||
|
||||
```{rust,ignore}
|
||||
while true {
|
||||
```
|
||||
|
||||
However, Rust has a dedicated keyword, `loop`, to handle this case:
|
||||
|
||||
```{rust,ignore}
|
||||
loop {
|
||||
```
|
||||
|
||||
Rust's control-flow analysis treats this construct differently than a
|
||||
`while true`, since we know that it will always loop. The details of what
|
||||
that _means_ aren't super important to understand at this stage, but in
|
||||
general, the more information we can give to the compiler, the better it
|
||||
can do with safety and code generation, so you should always prefer
|
||||
`loop` when you plan to loop infinitely.
|
||||
|
||||
## Ending iteration early
|
||||
|
||||
Let's take a look at that `while` loop we had earlier:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u;
|
||||
let mut done = false;
|
||||
|
||||
while !done {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { done = true; }
|
||||
}
|
||||
```
|
||||
|
||||
We had to keep a dedicated `mut` boolean variable binding, `done`, to know
|
||||
when we should exit out of the loop. Rust has two keywords to help us with
|
||||
modifying iteration: `break` and `continue`.
|
||||
|
||||
In this case, we can write the loop in a better way with `break`:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5u;
|
||||
|
||||
loop {
|
||||
x += x - 3;
|
||||
println!("{}", x);
|
||||
if x % 5 == 0 { break; }
|
||||
}
|
||||
```
|
||||
|
||||
We now loop forever with `loop` and use `break` to break out early.
|
||||
|
||||
`continue` is similar, but instead of ending the loop, goes to the next
|
||||
iteration. This will only print the odd numbers:
|
||||
|
||||
```{rust}
|
||||
for x in range(0, 10) {
|
||||
if x % 2 == 0 { continue; }
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
```
|
||||
|
||||
Both `continue` and `break` are valid in both kinds of loops.
|
@ -507,7 +507,7 @@ When this library is loaded with `#[use_macros] extern crate`, only `m2` will
|
||||
be imported.
|
||||
|
||||
The Rust Reference has a [listing of macro-related
|
||||
attributes](reference.html#macro--and-plugin-related-attributes).
|
||||
attributes](../reference.html#macro--and-plugin-related-attributes).
|
||||
|
||||
# The variable `$crate`
|
||||
|
||||
@ -567,7 +567,7 @@ intermediate states out, and passing the flag `--pretty expanded` as a
|
||||
command-line argument to the compiler will show the result of expansion.
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](guide-plugin.html) instead. Compared to `macro_rules!`
|
||||
[compiler plugin](plugin.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and the warnings about debugging apply ten-fold. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
156
src/doc/trpl/match.md
Normal file
156
src/doc/trpl/match.md
Normal file
@ -0,0 +1,156 @@
|
||||
% Match
|
||||
|
||||
Often, a simple `if`/`else` isn't enough, because you have more than two
|
||||
possible options. Also, `else` conditions can get incredibly complicated, so
|
||||
what's the solution?
|
||||
|
||||
Rust has a keyword, `match`, that allows you to replace complicated `if`/`else`
|
||||
groupings with something more powerful. Check it out:
|
||||
|
||||
```{rust}
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
1 => println!("one"),
|
||||
2 => println!("two"),
|
||||
3 => println!("three"),
|
||||
4 => println!("four"),
|
||||
5 => println!("five"),
|
||||
_ => println!("something else"),
|
||||
}
|
||||
```
|
||||
|
||||
`match` takes an expression and then branches based on its value. Each 'arm' of
|
||||
the branch is of the form `val => expression`. When the value matches, that arm's
|
||||
expression will be evaluated. It's called `match` because of the term 'pattern
|
||||
matching', which `match` is an implementation of.
|
||||
|
||||
So what's the big advantage here? Well, there are a few. First of all, `match`
|
||||
enforces 'exhaustiveness checking'. Do you see that last arm, the one with the
|
||||
underscore (`_`)? If we remove that arm, Rust will give us an error:
|
||||
|
||||
```text
|
||||
error: non-exhaustive patterns: `_` not covered
|
||||
```
|
||||
|
||||
In other words, Rust is trying to tell us we forgot a value. Because `x` is an
|
||||
integer, Rust knows that it can have a number of different values – for example,
|
||||
`6`. Without the `_`, however, there is no arm that could match, and so Rust refuses
|
||||
to compile. `_` acts like a 'catch-all arm'. If none of the other arms match,
|
||||
the arm with `_` will, and since we have this catch-all arm, we now have an arm
|
||||
for every possible value of `x`, and so our program will compile successfully.
|
||||
|
||||
`match` statements also destructure enums, as well. Remember this code from the
|
||||
section on enums?
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
let ordering = cmp(x, y);
|
||||
|
||||
if ordering == Ordering::Less {
|
||||
println!("less");
|
||||
} else if ordering == Ordering::Greater {
|
||||
println!("greater");
|
||||
} else if ordering == Ordering::Equal {
|
||||
println!("equal");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can re-write this as a `match`:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
match cmp(x, y) {
|
||||
Ordering::Less => println!("less"),
|
||||
Ordering::Greater => println!("greater"),
|
||||
Ordering::Equal => println!("equal"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This version has way less noise, and it also checks exhaustively to make sure
|
||||
that we have covered all possible variants of `Ordering`. With our `if`/`else`
|
||||
version, if we had forgotten the `Greater` case, for example, our program would
|
||||
have happily compiled. If we forget in the `match`, it will not. Rust helps us
|
||||
make sure to cover all of our bases.
|
||||
|
||||
`match` expressions also allow us to get the values contained in an `enum`
|
||||
(also known as destructuring) as follows:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = OptionalInt::Value(5);
|
||||
let y = OptionalInt::Missing;
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(n) => println!("x is {}", n),
|
||||
OptionalInt::Missing => println!("x is missing!"),
|
||||
}
|
||||
|
||||
match y {
|
||||
OptionalInt::Value(n) => println!("y is {}", n),
|
||||
OptionalInt::Missing => println!("y is missing!"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
That is how you can get and use the values contained in `enum`s.
|
||||
It can also allow us to handle errors or unexpected computations; for example, a
|
||||
function that is not guaranteed to be able to compute a result (an `i32` here)
|
||||
could return an `OptionalInt`, and we would handle that value with a `match`.
|
||||
As you can see, `enum` and `match` used together are quite useful!
|
||||
|
||||
`match` is also an expression, which means we can use it on the right-hand
|
||||
side of a `let` binding or directly where an expression is used. We could
|
||||
also implement the previous example like this:
|
||||
|
||||
```{rust}
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn cmp(a: i32, b: i32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = 10;
|
||||
|
||||
println!("{}", match cmp(x, y) {
|
||||
Ordering::Less => "less",
|
||||
Ordering::Greater => "greater",
|
||||
Ordering::Equal => "equal",
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes, it's a nice pattern.
|
88
src/doc/trpl/method-syntax.md
Normal file
88
src/doc/trpl/method-syntax.md
Normal file
@ -0,0 +1,88 @@
|
||||
% Method Syntax
|
||||
|
||||
Functions are great, but if you want to call a bunch of them on some data, it
|
||||
can be awkward. Consider this code:
|
||||
|
||||
```{rust,ignore}
|
||||
baz(bar(foo(x)));
|
||||
```
|
||||
|
||||
We would read this left-to right, and so we see 'baz bar foo.' But this isn't the
|
||||
order that the functions would get called in, that's inside-out: 'foo bar baz.'
|
||||
Wouldn't it be nice if we could do this instead?
|
||||
|
||||
```{rust,ignore}
|
||||
x.foo().bar().baz();
|
||||
```
|
||||
|
||||
Luckily, as you may have guessed with the leading question, you can! Rust provides
|
||||
the ability to use this **method call syntax** via the `impl` keyword.
|
||||
|
||||
Here's how it works:
|
||||
|
||||
```{rust}
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl Circle {
|
||||
fn area(&self) -> f64 {
|
||||
std::f64::consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = Circle { x: 0.0, y: 0.0, radius: 2.0 };
|
||||
println!("{}", c.area());
|
||||
}
|
||||
```
|
||||
|
||||
This will print `12.566371`.
|
||||
|
||||
We've made a struct that represents a circle. We then write an `impl` block,
|
||||
and inside it, define a method, `area`. Methods take a special first
|
||||
parameter, `&self`. There are three variants: `self`, `&self`, and `&mut self`.
|
||||
You can think of this first parameter as being the `x` in `x.foo()`. The three
|
||||
variants correspond to the three kinds of thing `x` could be: `self` if it's
|
||||
just a value on the stack, `&self` if it's a reference, and `&mut self` if it's
|
||||
a mutable reference. We should default to using `&self`, as it's the most
|
||||
common.
|
||||
|
||||
Finally, as you may remember, the value of the area of a circle is `π*r²`.
|
||||
Because we took the `&self` parameter to `area`, we can use it just like any
|
||||
other parameter. Because we know it's a `Circle`, we can access the `radius`
|
||||
just like we would with any other struct. An import of π and some
|
||||
multiplications later, and we have our area.
|
||||
|
||||
You can also define methods that do not take a `self` parameter. Here's a
|
||||
pattern that's very common in Rust code:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl Circle {
|
||||
fn new(x: f64, y: f64, radius: f64) -> Circle {
|
||||
Circle {
|
||||
x: x,
|
||||
y: y,
|
||||
radius: radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = Circle::new(0.0, 0.0, 2.0);
|
||||
}
|
||||
```
|
||||
|
||||
This **static method** builds a new `Circle` for us. Note that static methods
|
||||
are called with the `Struct::method()` syntax, rather than the `ref.method()`
|
||||
syntax.
|
||||
|
199
src/doc/trpl/patterns.md
Normal file
199
src/doc/trpl/patterns.md
Normal file
@ -0,0 +1,199 @@
|
||||
% Patterns
|
||||
|
||||
We've made use of patterns a few times in the guide: first with `let` bindings,
|
||||
then with `match` statements. Let's go on a whirlwind tour of all of the things
|
||||
patterns can do!
|
||||
|
||||
A quick refresher: you can match against literals directly, and `_` acts as an
|
||||
'any' case:
|
||||
|
||||
```{rust}
|
||||
let x = 1i;
|
||||
|
||||
match x {
|
||||
1 => println!("one"),
|
||||
2 => println!("two"),
|
||||
3 => println!("three"),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
You can match multiple patterns with `|`:
|
||||
|
||||
```{rust}
|
||||
let x = 1i;
|
||||
|
||||
match x {
|
||||
1 | 2 => println!("one or two"),
|
||||
3 => println!("three"),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
You can match a range of values with `...`:
|
||||
|
||||
```{rust}
|
||||
let x = 1i;
|
||||
|
||||
match x {
|
||||
1 ... 5 => println!("one through five"),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
Ranges are mostly used with integers and single characters.
|
||||
|
||||
If you're matching multiple things, via a `|` or a `...`, you can bind
|
||||
the value to a name with `@`:
|
||||
|
||||
```{rust}
|
||||
let x = 1i;
|
||||
|
||||
match x {
|
||||
e @ 1 ... 5 => println!("got a range element {}", e),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
If you're matching on an enum which has variants, you can use `..` to
|
||||
ignore the value and type in the variant:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(int),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalInt::Value(5i);
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(..) => println!("Got an int!"),
|
||||
OptionalInt::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
You can introduce **match guards** with `if`:
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(int),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalInt::Value(5i);
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
|
||||
OptionalInt::Value(..) => println!("Got an int!"),
|
||||
OptionalInt::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
If you're matching on a pointer, you can use the same syntax as you declared it
|
||||
with. First, `&`:
|
||||
|
||||
```{rust}
|
||||
let x = &5i;
|
||||
|
||||
match x {
|
||||
&val => println!("Got a value: {}", val),
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `val` inside the `match` has type `int`. In other words, the left-hand
|
||||
side of the pattern destructures the value. If we have `&5i`, then in `&val`, `val`
|
||||
would be `5i`.
|
||||
|
||||
If you want to get a reference, use the `ref` keyword:
|
||||
|
||||
```{rust}
|
||||
let x = 5i;
|
||||
|
||||
match x {
|
||||
ref r => println!("Got a reference to {}", r),
|
||||
}
|
||||
```
|
||||
|
||||
Here, the `r` inside the `match` has the type `&int`. In other words, the `ref`
|
||||
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
||||
reference, `ref mut` will work in the same way:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5i;
|
||||
|
||||
match x {
|
||||
ref mut mr => println!("Got a mutable reference to {}", mr),
|
||||
}
|
||||
```
|
||||
|
||||
If you have a struct, you can destructure it inside of a pattern:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
||||
|
||||
let origin = Point { x: 0i, y: 0i };
|
||||
|
||||
match origin {
|
||||
Point { x: x, y: y } => println!("({},{})", x, y),
|
||||
}
|
||||
```
|
||||
|
||||
If we only care about some of the values, we don't have to give them all names:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
||||
|
||||
let origin = Point { x: 0i, y: 0i };
|
||||
|
||||
match origin {
|
||||
Point { x: x, .. } => println!("x is {}", x),
|
||||
}
|
||||
```
|
||||
|
||||
You can do this kind of match on any member, not just the first:
|
||||
|
||||
```{rust}
|
||||
# #![allow(non_shorthand_field_patterns)]
|
||||
struct Point {
|
||||
x: int,
|
||||
y: int,
|
||||
}
|
||||
|
||||
let origin = Point { x: 0i, y: 0i };
|
||||
|
||||
match origin {
|
||||
Point { y: y, .. } => println!("y is {}", y),
|
||||
}
|
||||
```
|
||||
|
||||
If you want to match against a slice or array, you can use `[]`:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
|
||||
match v.as_slice() {
|
||||
["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Whew! That's a lot of different ways to match things, and they can all be
|
||||
mixed and matched, depending on what you're doing:
|
||||
|
||||
```{rust,ignore}
|
||||
match x {
|
||||
Foo { x: Some(ref name), y: None } => ...
|
||||
}
|
||||
```
|
||||
|
||||
Patterns are very powerful. Make good use of them.
|
@ -5,20 +5,20 @@
|
||||
<p>
|
||||
<b>Warning:</b> Plugins are an advanced, unstable feature! For many details,
|
||||
the only available documentation is the <a
|
||||
href="syntax/index.html"><code>libsyntax</code></a> and <a
|
||||
href="rustc/index.html"><code>librustc</code></a> API docs, or even the source
|
||||
href="../syntax/index.html"><code>libsyntax</code></a> and <a
|
||||
href="../rustc/index.html"><code>librustc</code></a> API docs, or even the source
|
||||
code itself. These internal compiler APIs are also subject to change at any
|
||||
time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For defining new syntax it is often much easier to use Rust's <a
|
||||
href="guide-macros.html">built-in macro system</a>.
|
||||
href="macros.html">built-in macro system</a>.
|
||||
</p>
|
||||
|
||||
<p style="margin-bottom: 0">
|
||||
The code in this document uses language features not covered in the Rust
|
||||
Guide. See the <a href="reference.html">Reference Manual</a> for more
|
||||
Guide. See the <a href="../reference.html">Reference Manual</a> for more
|
||||
information.
|
||||
</p>
|
||||
|
||||
@ -32,19 +32,19 @@ extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
||||
A plugin is a dynamic library crate with a designated "registrar" function that
|
||||
registers extensions with `rustc`. Other crates can use these extensions by
|
||||
loading the plugin crate with `#[plugin] extern crate`. See the
|
||||
[`rustc::plugin`](rustc/plugin/index.html) documentation for more about the
|
||||
[`rustc::plugin`](../rustc/plugin/index.html) documentation for more about the
|
||||
mechanics of defining and loading a plugin.
|
||||
|
||||
Arguments passed as `#[plugin=...]` or `#[plugin(...)]` are not interpreted by
|
||||
rustc itself. They are provided to the plugin through the `Registry`'s [`args`
|
||||
method](rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
method](../rustc/plugin/registry/struct.Registry.html#method.args).
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||
is the procedural macro. These are invoked the same way as [ordinary
|
||||
macros](guide-macros.html), but the expansion is performed by arbitrary Rust
|
||||
code that manipulates [syntax trees](syntax/ast/index.html) at
|
||||
macros](macros.html), but the expansion is performed by arbitrary Rust
|
||||
code that manipulates [syntax trees](../syntax/ast/index.html) at
|
||||
compile time.
|
||||
|
||||
Let's write a plugin
|
||||
@ -126,14 +126,13 @@ The advantages over a simple `fn(&str) -> uint` are:
|
||||
a way to define new literal syntax for any data type.
|
||||
|
||||
In addition to procedural macros, you can define new
|
||||
[`deriving`](reference.html#deriving)-like attributes and other kinds of
|
||||
[`deriving`](../reference.html#deriving)-like attributes and other kinds of
|
||||
extensions. See
|
||||
[`Registry::register_syntax_extension`](rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
and the [`SyntaxExtension`
|
||||
enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
|
||||
a more involved macro example, see
|
||||
[`src/libregex_macros/lib.rs`](https://github.com/rust-lang/rust/blob/master/src/libregex_macros/lib.rs)
|
||||
in the Rust distribution.
|
||||
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
|
||||
|
||||
|
||||
## Tips and tricks
|
||||
@ -147,7 +146,7 @@ variables of the same name (but different syntax contexts) are in play
|
||||
in the same scope. In this case `--pretty expanded,hygiene` will tell
|
||||
you about the syntax contexts.
|
||||
|
||||
You can use [`syntax::parse`](syntax/parse/index.html) to turn token trees into
|
||||
You can use [`syntax::parse`](../syntax/parse/index.html) to turn token trees into
|
||||
higher-level syntax elements like expressions:
|
||||
|
||||
```ignore
|
||||
@ -163,23 +162,23 @@ Looking through [`libsyntax` parser
|
||||
code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
|
||||
will give you a feel for how the parsing infrastructure works.
|
||||
|
||||
Keep the [`Span`s](syntax/codemap/struct.Span.html) of
|
||||
Keep the [`Span`s](../syntax/codemap/struct.Span.html) of
|
||||
everything you parse, for better error reporting. You can wrap
|
||||
[`Spanned`](syntax/codemap/struct.Spanned.html) around
|
||||
[`Spanned`](../syntax/codemap/struct.Spanned.html) around
|
||||
your custom data structures.
|
||||
|
||||
Calling
|
||||
[`ExtCtxt::span_fatal`](syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
|
||||
[`ExtCtxt::span_fatal`](../syntax/ext/base/struct.ExtCtxt.html#method.span_fatal)
|
||||
will immediately abort compilation. It's better to instead call
|
||||
[`ExtCtxt::span_err`](syntax/ext/base/struct.ExtCtxt.html#method.span_err)
|
||||
[`ExtCtxt::span_err`](../syntax/ext/base/struct.ExtCtxt.html#method.span_err)
|
||||
and return
|
||||
[`DummyResult`](syntax/ext/base/struct.DummyResult.html),
|
||||
[`DummyResult`](../syntax/ext/base/struct.DummyResult.html),
|
||||
so that the compiler can continue and find further errors.
|
||||
|
||||
The example above produced an integer literal using
|
||||
[`AstBuilder::expr_uint`](syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint).
|
||||
[`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint).
|
||||
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
|
||||
[quasiquote macros](syntax/ext/quote/index.html). They are undocumented and
|
||||
[quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and
|
||||
very rough around the edges. However, the implementation may be a good
|
||||
starting point for an improved quasiquote as an ordinary plugin library.
|
||||
|
||||
@ -187,7 +186,7 @@ starting point for an improved quasiquote as an ordinary plugin library.
|
||||
# Lint plugins
|
||||
|
||||
Plugins can extend [Rust's lint
|
||||
infrastructure](reference.html#lint-check-attributes) with additional checks for
|
||||
infrastructure](../reference.html#lint-check-attributes) with additional checks for
|
||||
code style, safety, etc. You can see
|
||||
[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
|
||||
for a full example, the core of which is reproduced here:
|
||||
@ -236,11 +235,11 @@ foo.rs:4 fn lintme() { }
|
||||
The components of a lint plugin are:
|
||||
|
||||
* one or more `declare_lint!` invocations, which define static
|
||||
[`Lint`](rustc/lint/struct.Lint.html) structs;
|
||||
[`Lint`](../rustc/lint/struct.Lint.html) structs;
|
||||
|
||||
* a struct holding any state needed by the lint pass (here, none);
|
||||
|
||||
* a [`LintPass`](rustc/lint/trait.LintPass.html)
|
||||
* a [`LintPass`](../rustc/lint/trait.LintPass.html)
|
||||
implementation defining how to check each syntax element. A single
|
||||
`LintPass` may call `span_lint` for several different `Lint`s, but should
|
||||
register them all through the `get_lints` method.
|
||||
@ -252,7 +251,7 @@ mostly use the same infrastructure as lint plugins, and provide examples of how
|
||||
to access type information.
|
||||
|
||||
Lints defined by plugins are controlled by the usual [attributes and compiler
|
||||
flags](reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
|
||||
flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
|
||||
`-A test-lint`. These identifiers are derived from the first argument to
|
||||
`declare_lint!`, with appropriate case and punctuation conversion.
|
||||
|
@ -409,7 +409,7 @@ test.rs:4 let y = &x;
|
||||
|
||||
As you might guess, this kind of analysis is complex for a human, and therefore
|
||||
hard for a computer, too! There is an entire [guide devoted to references, ownership,
|
||||
and lifetimes](guide-ownership.html) that goes into this topic in
|
||||
and lifetimes](ownership.html) that goes into this topic in
|
||||
great detail, so if you want the full details, check that out.
|
||||
|
||||
## Best practices
|
||||
@ -542,7 +542,7 @@ with some improvements:
|
||||
4. Rust enforces that no other writeable pointers alias to this heap memory,
|
||||
which means writing to an invalid pointer is not possible.
|
||||
|
||||
See the section on references or the [ownership guide](guide-ownership.html)
|
||||
See the section on references or the [ownership guide](ownership.html)
|
||||
for more detail on how lifetimes work.
|
||||
|
||||
Using boxes and references together is very common. For example:
|
||||
@ -780,6 +780,6 @@ Here's a quick rundown of Rust's pointer types:
|
||||
|
||||
# Related resources
|
||||
|
||||
* [API documentation for Box](std/boxed/index.html)
|
||||
* [Ownership guide](guide-ownership.html)
|
||||
* [API documentation for Box](../std/boxed/index.html)
|
||||
* [Ownership guide](ownership.html)
|
||||
* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system
|
59
src/doc/trpl/rust-book.css
Normal file
59
src/doc/trpl/rust-book.css
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
@import url("//static.rust-lang.org/doc/master/rust.css");
|
||||
|
||||
body {
|
||||
max-width:none;
|
||||
}
|
||||
|
||||
#toc {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
width: 250px;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
padding: 10px 10px;
|
||||
font-size: 16px;
|
||||
background: none repeat scroll 0% 0% #FFF;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#page-wrapper {
|
||||
position: absolute;
|
||||
overflow-y: auto;
|
||||
left: 260px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
box-sizing: border-box;
|
||||
background: none repeat scroll 0% 0% #FFF;
|
||||
}
|
||||
|
||||
#page {
|
||||
margin-left: auto;
|
||||
margin-right:auto;
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.chapter {
|
||||
list-style: none outside none;
|
||||
padding-left: 0px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.section {
|
||||
list-style: none outside none;
|
||||
padding-left: 20px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.section li {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chapter li a {
|
||||
color: #000000;
|
||||
}
|
159
src/doc/trpl/standard-input.md
Normal file
159
src/doc/trpl/standard-input.md
Normal file
@ -0,0 +1,159 @@
|
||||
% Standard Input
|
||||
|
||||
Getting input from the keyboard is pretty easy, but uses some things
|
||||
we haven't seen before. Here's a simple program that reads some input,
|
||||
and then prints it back out:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
println!("Type something!");
|
||||
|
||||
let input = std::io::stdin().read_line().ok().expect("Failed to read line");
|
||||
|
||||
println!("{}", input);
|
||||
}
|
||||
```
|
||||
|
||||
Let's go over these chunks, one by one:
|
||||
|
||||
```{rust,ignore}
|
||||
std::io::stdin();
|
||||
```
|
||||
|
||||
This calls a function, `stdin()`, that lives inside the `std::io` module. As
|
||||
you can imagine, everything in `std` is provided by Rust, the 'standard
|
||||
library.' We'll talk more about the module system later.
|
||||
|
||||
Since writing the fully qualified name all the time is annoying, we can use
|
||||
the `use` statement to import it in:
|
||||
|
||||
```{rust}
|
||||
use std::io::stdin;
|
||||
|
||||
stdin();
|
||||
```
|
||||
|
||||
However, it's considered better practice to not import individual functions, but
|
||||
to import the module, and only use one level of qualification:
|
||||
|
||||
```{rust}
|
||||
use std::io;
|
||||
|
||||
io::stdin();
|
||||
```
|
||||
|
||||
Let's update our example to use this style:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
|
||||
fn main() {
|
||||
println!("Type something!");
|
||||
|
||||
let input = io::stdin().read_line().ok().expect("Failed to read line");
|
||||
|
||||
println!("{}", input);
|
||||
}
|
||||
```
|
||||
|
||||
Next up:
|
||||
|
||||
```{rust,ignore}
|
||||
.read_line()
|
||||
```
|
||||
|
||||
The `read_line()` method can be called on the result of `stdin()` to return
|
||||
a full line of input. Nice and easy.
|
||||
|
||||
```{rust,ignore}
|
||||
.ok().expect("Failed to read line");
|
||||
```
|
||||
|
||||
Do you remember this code?
|
||||
|
||||
```{rust}
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = OptionalInt::Value(5);
|
||||
let y = OptionalInt::Missing;
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(n) => println!("x is {}", n),
|
||||
OptionalInt::Missing => println!("x is missing!"),
|
||||
}
|
||||
|
||||
match y {
|
||||
OptionalInt::Value(n) => println!("y is {}", n),
|
||||
OptionalInt::Missing => println!("y is missing!"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We had to match each time to see if we had a value or not. In this case,
|
||||
though, we _know_ that `x` has a `Value`, but `match` forces us to handle
|
||||
the `missing` case. This is what we want 99% of the time, but sometimes, we
|
||||
know better than the compiler.
|
||||
|
||||
Likewise, `read_line()` does not return a line of input. It _might_ return a
|
||||
line of input, though it might also fail to do so. This could happen if our program
|
||||
isn't running in a terminal, but as part of a cron job, or some other context
|
||||
where there's no standard input. Because of this, `read_line` returns a type
|
||||
very similar to our `OptionalInt`: an `IoResult<T>`. We haven't talked about
|
||||
`IoResult<T>` yet because it is the **generic** form of our `OptionalInt`.
|
||||
Until then, you can think of it as being the same thing, just for any type –
|
||||
not just `i32`s.
|
||||
|
||||
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
|
||||
same thing as our `match` statement but assumes that we have a valid value.
|
||||
We then call `expect()` on the result, which will terminate our program if we
|
||||
don't have a valid value. In this case, if we can't get input, our program
|
||||
doesn't work, so we're okay with that. In most cases, we would want to handle
|
||||
the error case explicitly. `expect()` allows us to give an error message if
|
||||
this crash happens.
|
||||
|
||||
We will cover the exact details of how all of this works later in the Guide.
|
||||
For now, this gives you enough of a basic understanding to work with.
|
||||
|
||||
Back to the code we were working on! Here's a refresher:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
|
||||
fn main() {
|
||||
println!("Type something!");
|
||||
|
||||
let input = io::stdin().read_line().ok().expect("Failed to read line");
|
||||
|
||||
println!("{}", input);
|
||||
}
|
||||
```
|
||||
|
||||
With long lines like this, Rust gives you some flexibility with the whitespace.
|
||||
We _could_ write the example like this:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
|
||||
fn main() {
|
||||
println!("Type something!");
|
||||
|
||||
// here, we'll show the types at each step
|
||||
|
||||
let input = io::stdin() // std::io::stdio::StdinReader
|
||||
.read_line() // IoResult<String>
|
||||
.ok() // Option<String>
|
||||
.expect("Failed to read line"); // String
|
||||
|
||||
println!("{}", input);
|
||||
}
|
||||
```
|
||||
|
||||
Sometimes, this makes things more readable – sometimes, less. Use your judgement
|
||||
here.
|
||||
|
||||
That's all you need to get basic input from the standard input! It's not too
|
||||
complicated, but there are a number of small parts.
|
79
src/doc/trpl/strings.md
Normal file
79
src/doc/trpl/strings.md
Normal file
@ -0,0 +1,79 @@
|
||||
% Strings
|
||||
|
||||
Strings are an important concept for any programmer to master. Rust's string
|
||||
handling system is a bit different from other languages, due to its systems
|
||||
focus. Any time you have a data structure of variable size, things can get
|
||||
tricky, and strings are a re-sizable data structure. That being said, Rust's
|
||||
strings also work differently than in some other systems languages, such as C.
|
||||
|
||||
Let's dig into the details. A **string** is a sequence of Unicode scalar values
|
||||
encoded as a stream of UTF-8 bytes. All strings are guaranteed to be
|
||||
validly encoded UTF-8 sequences. Additionally, strings are not null-terminated
|
||||
and can contain null bytes.
|
||||
|
||||
Rust has two main types of strings: `&str` and `String`.
|
||||
|
||||
The first kind is a `&str`. This is pronounced a 'string slice.' String literals
|
||||
are of the type `&str`:
|
||||
|
||||
```{rust}
|
||||
let string = "Hello there."; // string: &str
|
||||
```
|
||||
|
||||
This string is statically allocated, meaning that it's saved inside our
|
||||
compiled program, and exists for the entire duration it runs. The `string`
|
||||
binding is a reference to this statically allocated string. String slices
|
||||
have a fixed size, and cannot be mutated.
|
||||
|
||||
A `String`, on the other hand, is an in-memory string. This string is
|
||||
growable, and is also guaranteed to be UTF-8.
|
||||
|
||||
```{rust}
|
||||
let mut s = "Hello".to_string(); // mut s: String
|
||||
println!("{}", s);
|
||||
|
||||
s.push_str(", world.");
|
||||
println!("{}", s);
|
||||
```
|
||||
|
||||
You can get a `&str` view into a `String` with the `as_slice()` method:
|
||||
|
||||
```{rust}
|
||||
fn takes_slice(slice: &str) {
|
||||
println!("Got: {}", slice);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = "Hello".to_string();
|
||||
takes_slice(s.as_slice());
|
||||
}
|
||||
```
|
||||
|
||||
To compare a String to a constant string, prefer `as_slice()`...
|
||||
|
||||
```{rust}
|
||||
fn compare(string: String) {
|
||||
if string.as_slice() == "Hello" {
|
||||
println!("yes");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
... over `to_string()`:
|
||||
|
||||
```{rust}
|
||||
fn compare(string: String) {
|
||||
if string == "Hello".to_string() {
|
||||
println!("yes");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Viewing a `String` as a `&str` is cheap, but converting the `&str` to a
|
||||
`String` involves allocating memory. No reason to do that unless you have to!
|
||||
|
||||
That's the basics of strings in Rust! They're probably a bit more complicated
|
||||
than you are used to, if you come from a scripting language, but when the
|
||||
low-level details matter, they really matter. Just remember that `String`s
|
||||
allocate memory and control their data, while `&str`s are a reference to
|
||||
another string, and you'll be all set.
|
@ -369,7 +369,7 @@ Unlike `spawn`, the function spawned using `try` may return a value, which
|
||||
child thread terminates successfully, `try` will return an `Ok` result; if the
|
||||
child thread panics, `try` will return an `Error` result.
|
||||
|
||||
[`Result`]: std/result/index.html
|
||||
[`Result`]: ../std/result/index.html
|
||||
|
||||
> *Note:* A panicked thread does not currently produce a useful error
|
||||
> value (`try` always returns `Err(())`). In the
|
317
src/doc/trpl/traits.md
Normal file
317
src/doc/trpl/traits.md
Normal file
@ -0,0 +1,317 @@
|
||||
% Traits
|
||||
|
||||
Do you remember the `impl` keyword, used to call a function with method
|
||||
syntax?
|
||||
|
||||
```{rust}
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl Circle {
|
||||
fn area(&self) -> f64 {
|
||||
std::f64::consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Traits are similar, except that we define a trait with just the method
|
||||
signature, then implement the trait for that struct. Like this:
|
||||
|
||||
```{rust}
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
}
|
||||
|
||||
impl HasArea for Circle {
|
||||
fn area(&self) -> f64 {
|
||||
std::f64::consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, the `trait` block looks very similar to the `impl` block,
|
||||
but we don't define a body, just a type signature. When we `impl` a trait,
|
||||
we use `impl Trait for Item`, rather than just `impl Item`.
|
||||
|
||||
So what's the big deal? Remember the error we were getting with our generic
|
||||
`inverse` function?
|
||||
|
||||
```text
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
We can use traits to constrain our generics. Consider this function, which
|
||||
does not compile, and gives us a similar error:
|
||||
|
||||
```{rust,ignore}
|
||||
fn print_area<T>(shape: T) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
```
|
||||
|
||||
Rust complains:
|
||||
|
||||
```text
|
||||
error: type `T` does not implement any method in scope named `area`
|
||||
```
|
||||
|
||||
Because `T` can be any type, we can't be sure that it implements the `area`
|
||||
method. But we can add a **trait constraint** to our generic `T`, ensuring
|
||||
that it does:
|
||||
|
||||
```{rust}
|
||||
# trait HasArea {
|
||||
# fn area(&self) -> f64;
|
||||
# }
|
||||
fn print_area<T: HasArea>(shape: T) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
```
|
||||
|
||||
The syntax `<T: HasArea>` means `any type that implements the HasArea trait`.
|
||||
Because traits define function type signatures, we can be sure that any type
|
||||
which implements `HasArea` will have an `.area()` method.
|
||||
|
||||
Here's an extended example of how this works:
|
||||
|
||||
```{rust}
|
||||
trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
}
|
||||
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl HasArea for Circle {
|
||||
fn area(&self) -> f64 {
|
||||
std::f64::consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
|
||||
struct Square {
|
||||
x: f64,
|
||||
y: f64,
|
||||
side: f64,
|
||||
}
|
||||
|
||||
impl HasArea for Square {
|
||||
fn area(&self) -> f64 {
|
||||
self.side * self.side
|
||||
}
|
||||
}
|
||||
|
||||
fn print_area<T: HasArea>(shape: T) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = Circle {
|
||||
x: 0.0f64,
|
||||
y: 0.0f64,
|
||||
radius: 1.0f64,
|
||||
};
|
||||
|
||||
let s = Square {
|
||||
x: 0.0f64,
|
||||
y: 0.0f64,
|
||||
side: 1.0f64,
|
||||
};
|
||||
|
||||
print_area(c);
|
||||
print_area(s);
|
||||
}
|
||||
```
|
||||
|
||||
This program outputs:
|
||||
|
||||
```text
|
||||
This shape has an area of 3.141593
|
||||
This shape has an area of 1
|
||||
```
|
||||
|
||||
As you can see, `print_area` is now generic, but also ensures that we
|
||||
have passed in the correct types. If we pass in an incorrect type:
|
||||
|
||||
```{rust,ignore}
|
||||
print_area(5i);
|
||||
```
|
||||
|
||||
We get a compile-time error:
|
||||
|
||||
```text
|
||||
error: failed to find an implementation of trait main::HasArea for int
|
||||
```
|
||||
|
||||
So far, we've only added trait implementations to structs, but you can
|
||||
implement a trait for any type. So technically, we _could_ implement
|
||||
`HasArea` for `int`:
|
||||
|
||||
```{rust}
|
||||
trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
}
|
||||
|
||||
impl HasArea for int {
|
||||
fn area(&self) -> f64 {
|
||||
println!("this is silly");
|
||||
|
||||
*self as f64
|
||||
}
|
||||
}
|
||||
|
||||
5i.area();
|
||||
```
|
||||
|
||||
It is considered poor style to implement methods on such primitive types, even
|
||||
though it is possible.
|
||||
|
||||
This may seem like the Wild West, but there are two other restrictions around
|
||||
implementing traits that prevent this from getting out of hand. First, traits
|
||||
must be `use`d in any scope where you wish to use the trait's method. So for
|
||||
example, this does not work:
|
||||
|
||||
```{rust,ignore}
|
||||
mod shapes {
|
||||
use std::f64::consts;
|
||||
|
||||
trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
}
|
||||
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
impl HasArea for Circle {
|
||||
fn area(&self) -> f64 {
|
||||
consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = shapes::Circle {
|
||||
x: 0.0f64,
|
||||
y: 0.0f64,
|
||||
radius: 1.0f64,
|
||||
};
|
||||
|
||||
println!("{}", c.area());
|
||||
}
|
||||
```
|
||||
|
||||
Now that we've moved the structs and traits into their own module, we get an
|
||||
error:
|
||||
|
||||
```text
|
||||
error: type `shapes::Circle` does not implement any method in scope named `area`
|
||||
```
|
||||
|
||||
If we add a `use` line right above `main` and make the right things public,
|
||||
everything is fine:
|
||||
|
||||
```{rust}
|
||||
use shapes::HasArea;
|
||||
|
||||
mod shapes {
|
||||
use std::f64::consts;
|
||||
|
||||
pub trait HasArea {
|
||||
fn area(&self) -> f64;
|
||||
}
|
||||
|
||||
pub struct Circle {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub radius: f64,
|
||||
}
|
||||
|
||||
impl HasArea for Circle {
|
||||
fn area(&self) -> f64 {
|
||||
consts::PI * (self.radius * self.radius)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let c = shapes::Circle {
|
||||
x: 0.0f64,
|
||||
y: 0.0f64,
|
||||
radius: 1.0f64,
|
||||
};
|
||||
|
||||
println!("{}", c.area());
|
||||
}
|
||||
```
|
||||
|
||||
This means that even if someone does something bad like add methods to `int`,
|
||||
it won't affect you, unless you `use` that trait.
|
||||
|
||||
There's one more restriction on implementing traits. Either the trait or the
|
||||
type you're writing the `impl` for must be inside your crate. So, we could
|
||||
implement the `HasArea` type for `int`, because `HasArea` is in our crate. But
|
||||
if we tried to implement `Float`, a trait provided by Rust, for `int`, we could
|
||||
not, because both the trait and the type aren't in our crate.
|
||||
|
||||
One last thing about traits: generic functions with a trait bound use
|
||||
**monomorphization** ("mono": one, "morph": form), so they are statically
|
||||
dispatched. What's that mean? Well, let's take a look at `print_area` again:
|
||||
|
||||
```{rust,ignore}
|
||||
fn print_area<T: HasArea>(shape: T) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = Circle { ... };
|
||||
|
||||
let s = Square { ... };
|
||||
|
||||
print_area(c);
|
||||
print_area(s);
|
||||
}
|
||||
```
|
||||
|
||||
When we use this trait with `Circle` and `Square`, Rust ends up generating
|
||||
two different functions with the concrete type, and replacing the call sites with
|
||||
calls to the concrete implementations. In other words, you get something like
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn __print_area_circle(shape: Circle) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
|
||||
fn __print_area_square(shape: Square) {
|
||||
println!("This shape has an area of {}", shape.area());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let c = Circle { ... };
|
||||
|
||||
let s = Square { ... };
|
||||
|
||||
__print_area_circle(c);
|
||||
__print_area_square(s);
|
||||
}
|
||||
```
|
||||
|
||||
The names don't actually change to this, it's just for illustration. But
|
||||
as you can see, there's no overhead of deciding which version to call here,
|
||||
hence 'statically dispatched.' The downside is that we have two copies of
|
||||
the same function, so our binary is a little bit larger.
|
@ -12,7 +12,7 @@ block which allows the programmer to dodge some of the compiler's
|
||||
checks and do a wide range of operations, such as:
|
||||
|
||||
- dereferencing [raw pointers](#raw-pointers)
|
||||
- calling a function via FFI ([covered by the FFI guide](guide-ffi.html))
|
||||
- calling a function via FFI ([covered by the FFI guide](ffi.html))
|
||||
- casting between types bitwise (`transmute`, aka "reinterpret cast")
|
||||
- [inline assembly](#inline-assembly)
|
||||
|
||||
@ -37,7 +37,7 @@ build safe interfaces.
|
||||
## References
|
||||
|
||||
One of Rust's biggest features is memory safety. This is achieved in
|
||||
part via [the ownership system](guide-ownership.html), which is how the
|
||||
part via [the ownership system](ownership.html), which is how the
|
||||
compiler can guarantee that every `&` reference is always valid, and,
|
||||
for example, never pointing to freed memory.
|
||||
|
||||
@ -504,7 +504,7 @@ shouldn't get triggered.
|
||||
The second of these three functions, `eh_personality`, is used by the
|
||||
failure mechanisms of the compiler. This is often mapped to GCC's
|
||||
personality function (see the
|
||||
[libstd implementation](std/rt/unwind/index.html) for more
|
||||
[libstd implementation](../std/rt/unwind/index.html) for more
|
||||
information), but crates which do not trigger a panic can be assured
|
||||
that this function is never called. The final function, `panic_fmt`, is
|
||||
also used by the failure mechanisms of the compiler.
|
||||
@ -517,7 +517,7 @@ also used by the failure mechanisms of the compiler.
|
||||
With the above techniques, we've got a bare-metal executable running some Rust
|
||||
code. There is a good deal of functionality provided by the standard library,
|
||||
however, that is necessary to be productive in Rust. If the standard library is
|
||||
not sufficient, then [libcore](core/index.html) is designed to be used
|
||||
not sufficient, then [libcore](../core/index.html) is designed to be used
|
||||
instead.
|
||||
|
||||
The core library has very few dependencies and is much more portable than the
|
174
src/doc/trpl/variable-bindings.md
Normal file
174
src/doc/trpl/variable-bindings.md
Normal file
@ -0,0 +1,174 @@
|
||||
% Variable bindings
|
||||
|
||||
The first thing we'll learn about are 'variable bindings.' They look like this:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let x = 5;
|
||||
}
|
||||
```
|
||||
|
||||
Putting `fn main() {` in each example is a bit tedious, so we'll leave that out
|
||||
in the future. If you're following along, make sure to edit your `main()`
|
||||
function, rather than leaving it off. Otherwise, you'll get an error.
|
||||
|
||||
In many languages, this is called a 'variable.' But Rust's variable bindings
|
||||
have a few tricks up their sleeves. Rust has a very powerful feature called
|
||||
'pattern matching' that we'll get into detail with later, but the left
|
||||
hand side of a `let` expression is a full pattern, not just a variable name.
|
||||
This means we can do things like:
|
||||
|
||||
```{rust}
|
||||
let (x, y) = (1, 2);
|
||||
```
|
||||
|
||||
After this expression is evaluated, `x` will be one, and `y` will be two.
|
||||
Patterns are really powerful, but this is about all we can do with them so far.
|
||||
So let's just keep this in the back of our minds as we go forward.
|
||||
|
||||
Rust is a statically typed language, which means that we specify our types up
|
||||
front. So why does our first example compile? Well, Rust has this thing called
|
||||
"type inference." If it can figure out what the type of something is, Rust
|
||||
doesn't require you to actually type it out.
|
||||
|
||||
We can add the type if we want to, though. Types come after a colon (`:`):
|
||||
|
||||
```{rust}
|
||||
let x: i32 = 5;
|
||||
```
|
||||
|
||||
If I asked you to read this out loud to the rest of the class, you'd say "`x`
|
||||
is a binding with the type `i32` and the value `five`."
|
||||
|
||||
In future examples, we may annotate the type in a comment. The examples will
|
||||
look like this:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let x = 5; // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
Note the similarities between this annotation and the syntax you use with `let`.
|
||||
Including these kinds of comments is not idiomatic Rust, but we'll occasionally
|
||||
include them to help you understand what the types that Rust infers are.
|
||||
|
||||
By default, bindings are **immutable**. This code will not compile:
|
||||
|
||||
```{ignore}
|
||||
let x = 5;
|
||||
x = 10;
|
||||
```
|
||||
|
||||
It will give you this error:
|
||||
|
||||
```text
|
||||
error: re-assignment of immutable variable `x`
|
||||
x = 10;
|
||||
^~~~~~~
|
||||
```
|
||||
|
||||
If you want a binding to be mutable, you can use `mut`:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5; // mut x: i32
|
||||
x = 10;
|
||||
```
|
||||
|
||||
There is no single reason that bindings are immutable by default, but we can
|
||||
think about it through one of Rust's primary focuses: safety. If you forget to
|
||||
say `mut`, the compiler will catch it, and let you know that you have mutated
|
||||
something you may not have intended to mutate. If bindings were mutable by
|
||||
default, the compiler would not be able to tell you this. If you _did_ intend
|
||||
mutation, then the solution is quite easy: add `mut`.
|
||||
|
||||
There are other good reasons to avoid mutable state when possible, but they're
|
||||
out of the scope of this guide. In general, you can often avoid explicit
|
||||
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
|
||||
what you need, so it's not verboten.
|
||||
|
||||
Let's get back to bindings. Rust variable bindings have one more aspect that
|
||||
differs from other languages: bindings are required to be initialized with a
|
||||
value before you're allowed to use them. If we try...
|
||||
|
||||
```{ignore}
|
||||
let x;
|
||||
```
|
||||
|
||||
...we'll get an error:
|
||||
|
||||
```text
|
||||
src/main.rs:2:9: 2:10 error: cannot determine a type for this local variable: unconstrained type
|
||||
src/main.rs:2 let x;
|
||||
^
|
||||
```
|
||||
|
||||
Giving it a type will compile, though:
|
||||
|
||||
```{rust}
|
||||
let x: i32;
|
||||
```
|
||||
|
||||
Let's try it out. Change your `src/main.rs` file to look like this:
|
||||
|
||||
```{rust}
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
println!("Hello world!");
|
||||
}
|
||||
```
|
||||
|
||||
You can use `cargo build` on the command line to build it. You'll get a warning,
|
||||
but it will still print "Hello, world!":
|
||||
|
||||
```text
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
|
||||
src/main.rs:2 let x: i32;
|
||||
^
|
||||
```
|
||||
|
||||
Rust warns us that we never use the variable binding, but since we never use it,
|
||||
no harm, no foul. Things change if we try to actually use this `x`, however. Let's
|
||||
do that. Change your program to look like this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
println!("The value of x is: {}", x);
|
||||
}
|
||||
```
|
||||
|
||||
And try to build it. You'll get an error:
|
||||
|
||||
```{bash}
|
||||
$ cargo build
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x`
|
||||
src/main.rs:4 println!("The value of x is: {}", x);
|
||||
^
|
||||
note: in expansion of format_args!
|
||||
<std macros>:2:23: 2:77 note: expansion site
|
||||
<std macros>:1:1: 3:2 note: in expansion of println!
|
||||
src/main.rs:4:5: 4:42 note: expansion site
|
||||
error: aborting due to previous error
|
||||
Could not compile `hello_world`.
|
||||
```
|
||||
|
||||
Rust will not let us use a value that has not been initialized. Next, let's
|
||||
talk about this stuff we've added to `println!`.
|
||||
|
||||
If you include two curly braces (`{}`, some call them moustaches...) in your
|
||||
string to print, Rust will interpret this as a request to interpolate some sort
|
||||
of value. **String interpolation** is a computer science term that means "stick
|
||||
in the middle of a string." We add a comma, and then `x`, to indicate that we
|
||||
want `x` to be the value we're interpolating. The comma is used to separate
|
||||
arguments we pass to functions and macros, if you're passing more than one.
|
||||
|
||||
When you just use the curly braces, Rust will attempt to display the
|
||||
value in a meaningful way by checking out its type. If you want to specify the
|
||||
format in a more detailed manner, there are a [wide number of options
|
||||
available](../std/fmt/index.html). For now, we'll just stick to the default:
|
||||
integers aren't very complicated to print.
|
@ -126,7 +126,7 @@ unsafe impl<T: Sync + Send> Sync for Arc<T> { }
|
||||
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be used to break cycles
|
||||
/// between `Arc` pointers.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
pub struct Weak<T> {
|
||||
// FIXME #12808: strange name to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
@ -179,7 +179,7 @@ impl<T> Arc<T> {
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
// See the clone() impl for why this is relaxed
|
||||
self.inner().weak.fetch_add(1, Relaxed);
|
||||
@ -200,12 +200,12 @@ impl<T> Arc<T> {
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn weak_count<T>(this: &Arc<T>) -> uint { this.inner().weak.load(SeqCst) - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn strong_count<T>(this: &Arc<T>) -> uint { this.inner().strong.load(SeqCst) }
|
||||
|
||||
#[stable]
|
||||
@ -271,7 +271,7 @@ impl<T: Send + Sync + Clone> Arc<T> {
|
||||
/// let mut_five = five.make_unique();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn make_unique(&mut self) -> &mut T {
|
||||
// Note that we hold a strong reference, which also counts as a weak reference, so we only
|
||||
// clone if there is an additional reference of either kind.
|
||||
@ -355,7 +355,7 @@ impl<T: Sync + Send> Drop for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
impl<T: Sync + Send> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
@ -393,7 +393,7 @@ impl<T: Sync + Send> Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
impl<T: Sync + Send> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
@ -604,7 +604,7 @@ impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(experimental)]
|
||||
#[allow(unstable)]
|
||||
mod tests {
|
||||
use std::clone::Clone;
|
||||
use std::sync::mpsc::channel;
|
||||
|
@ -44,7 +44,7 @@ use core::ops::{Deref, DerefMut};
|
||||
/// }
|
||||
/// ```
|
||||
#[lang = "exchange_heap"]
|
||||
#[experimental = "may be renamed; uncertain about custom allocator design"]
|
||||
#[unstable = "may be renamed; uncertain about custom allocator design"]
|
||||
pub static HEAP: () = ();
|
||||
|
||||
/// A type that represents a uniquely-owned value.
|
||||
|
@ -57,7 +57,7 @@
|
||||
//! default global allocator. It is not compatible with the libc allocator API.
|
||||
|
||||
#![crate_name = "alloc"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
@ -68,6 +68,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![feature(lang_items, unsafe_destructor)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate core;
|
||||
|
@ -221,7 +221,7 @@ impl<T> Rc<T> {
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[experimental = "Weak pointers may not belong in this module"]
|
||||
#[unstable = "Weak pointers may not belong in this module"]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak {
|
||||
@ -234,12 +234,12 @@ impl<T> Rc<T> {
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn weak_count<T>(this: &Rc<T>) -> uint { this.weak() - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn strong_count<T>(this: &Rc<T>) -> uint { this.strong() }
|
||||
|
||||
/// Returns true if there are no other `Rc` or `Weak<T>` values that share the same inner value.
|
||||
@ -255,7 +255,7 @@ pub fn strong_count<T>(this: &Rc<T>) -> uint { this.strong() }
|
||||
/// rc::is_unique(&five);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn is_unique<T>(rc: &Rc<T>) -> bool {
|
||||
weak_count(rc) == 0 && strong_count(rc) == 1
|
||||
}
|
||||
@ -277,7 +277,7 @@ pub fn is_unique<T>(rc: &Rc<T>) -> bool {
|
||||
/// assert_eq!(rc::try_unwrap(x), Err(Rc::new(4u)));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> {
|
||||
if is_unique(&rc) {
|
||||
unsafe {
|
||||
@ -311,7 +311,7 @@ pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> {
|
||||
/// assert!(rc::get_mut(&mut x).is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn get_mut<'a, T>(rc: &'a mut Rc<T>) -> Option<&'a mut T> {
|
||||
if is_unique(rc) {
|
||||
let inner = unsafe { &mut **rc._ptr };
|
||||
@ -337,7 +337,7 @@ impl<T: Clone> Rc<T> {
|
||||
/// let mut_five = five.make_unique();
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn make_unique(&mut self) -> &mut T {
|
||||
if !is_unique(self) {
|
||||
*self = Rc::new((**self).clone())
|
||||
@ -615,7 +615,7 @@ impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Show is experimental."]
|
||||
#[unstable = "Show is experimental."]
|
||||
impl<T: fmt::Show> fmt::Show for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Rc({:?})", **self)
|
||||
@ -635,7 +635,7 @@ impl<T: fmt::String> fmt::String for Rc<T> {
|
||||
///
|
||||
/// See the [module level documentation](../index.html) for more.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
pub struct Weak<T> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
@ -644,7 +644,7 @@ pub struct Weak<T> {
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
impl<T> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
@ -717,7 +717,7 @@ impl<T> Drop for Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
#[unstable = "Weak pointers may not belong in this module."]
|
||||
impl<T> Clone for Weak<T> {
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
@ -739,7 +739,7 @@ impl<T> Clone for Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Show is experimental."]
|
||||
#[unstable = "Show is experimental."]
|
||||
impl<T: fmt::Show> fmt::Show for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
@ -780,7 +780,7 @@ impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(experimental)]
|
||||
#[allow(unstable)]
|
||||
mod tests {
|
||||
use super::{Rc, Weak, weak_count, strong_count};
|
||||
use std::cell::RefCell;
|
||||
|
@ -20,7 +20,7 @@
|
||||
//! more complex, slower arena which can hold objects of any type.
|
||||
|
||||
#![crate_name = "arena"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -32,6 +32,7 @@
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
extern crate alloc;
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
|
||||
#![crate_name = "collections"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
@ -27,6 +27,7 @@
|
||||
#![feature(box_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(old_impl_check)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -166,7 +166,7 @@ pub trait SliceExt {
|
||||
/// assert_eq!(num_moved, 3);
|
||||
/// assert!(a == [6i, 7, 8, 4, 5]);
|
||||
/// ```
|
||||
#[experimental = "uncertain about this API approach"]
|
||||
#[unstable = "uncertain about this API approach"]
|
||||
fn move_from(&mut self, src: Vec<Self::Item>, start: uint, end: uint) -> uint;
|
||||
|
||||
/// Returns a subslice spanning the interval [`start`, `end`).
|
||||
@ -175,7 +175,7 @@ pub trait SliceExt {
|
||||
/// original slice (i.e. when `end > self.len()`) or when `start > end`.
|
||||
///
|
||||
/// Slicing with `start` equal to `end` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice(&self, start: uint, end: uint) -> &[Self::Item];
|
||||
|
||||
/// Returns a subslice from `start` to the end of the slice.
|
||||
@ -183,7 +183,7 @@ pub trait SliceExt {
|
||||
/// Panics when `start` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing from `self.len()` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice_from(&self, start: uint) -> &[Self::Item];
|
||||
|
||||
/// Returns a subslice from the start of the slice to `end`.
|
||||
@ -191,7 +191,7 @@ pub trait SliceExt {
|
||||
/// Panics when `end` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing to `0` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice_to(&self, end: uint) -> &[Self::Item];
|
||||
|
||||
/// Divides one slice into two at an index.
|
||||
@ -284,11 +284,11 @@ pub trait SliceExt {
|
||||
fn first(&self) -> Option<&Self::Item>;
|
||||
|
||||
/// Returns all but the first element of a slice.
|
||||
#[experimental = "likely to be renamed"]
|
||||
#[unstable = "likely to be renamed"]
|
||||
fn tail(&self) -> &[Self::Item];
|
||||
|
||||
/// Returns all but the last element of a slice.
|
||||
#[experimental = "likely to be renamed"]
|
||||
#[unstable = "likely to be renamed"]
|
||||
fn init(&self) -> &[Self::Item];
|
||||
|
||||
/// Returns the last element of a slice, or `None` if it is empty.
|
||||
@ -384,7 +384,7 @@ pub trait SliceExt {
|
||||
/// original slice (i.e. when `end > self.len()`) or when `start > end`.
|
||||
///
|
||||
/// Slicing with `start` equal to `end` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice_mut(&mut self, start: uint, end: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable subslice from `start` to the end of the slice.
|
||||
@ -392,7 +392,7 @@ pub trait SliceExt {
|
||||
/// Panics when `start` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing from `self.len()` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice_from_mut(&mut self, start: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable subslice from the start of the slice to `end`.
|
||||
@ -400,7 +400,7 @@ pub trait SliceExt {
|
||||
/// Panics when `end` is strictly greater than the length of the original slice.
|
||||
///
|
||||
/// Slicing to `0` yields an empty slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
fn slice_to_mut(&mut self, end: uint) -> &mut [Self::Item];
|
||||
|
||||
/// Returns an iterator that allows modifying each value
|
||||
@ -412,11 +412,11 @@ pub trait SliceExt {
|
||||
fn first_mut(&mut self) -> Option<&mut Self::Item>;
|
||||
|
||||
/// Returns all but the first element of a mutable slice
|
||||
#[experimental = "likely to be renamed or removed"]
|
||||
#[unstable = "likely to be renamed or removed"]
|
||||
fn tail_mut(&mut self) -> &mut [Self::Item];
|
||||
|
||||
/// Returns all but the last element of a mutable slice
|
||||
#[experimental = "likely to be renamed or removed"]
|
||||
#[unstable = "likely to be renamed or removed"]
|
||||
fn init_mut(&mut self) -> &mut [Self::Item];
|
||||
|
||||
/// Returns a mutable pointer to the last item in the slice.
|
||||
@ -588,7 +588,7 @@ pub trait SliceExt {
|
||||
/// assert!(dst.clone_from_slice(&src2) == 3);
|
||||
/// assert!(dst == [3i, 4, 5]);
|
||||
/// ```
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn clone_from_slice(&mut self, &[Self::Item]) -> uint where Self::Item: Clone;
|
||||
|
||||
/// Sorts the slice, in place.
|
||||
@ -677,11 +677,11 @@ pub trait SliceExt {
|
||||
fn prev_permutation(&mut self) -> bool where Self::Item: Ord;
|
||||
|
||||
/// Find the first index containing a matching value.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn position_elem(&self, t: &Self::Item) -> Option<uint> where Self::Item: PartialEq;
|
||||
|
||||
/// Find the last index containing a matching value.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn rposition_elem(&self, t: &Self::Item) -> Option<uint> where Self::Item: PartialEq;
|
||||
|
||||
/// Return true if the slice contains an element with the given value.
|
||||
@ -697,7 +697,7 @@ pub trait SliceExt {
|
||||
fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
|
||||
|
||||
/// Convert `self` into a vector without clones or allocation.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn into_vec(self: Box<Self>) -> Vec<Self::Item>;
|
||||
}
|
||||
|
||||
@ -1034,7 +1034,7 @@ impl<T: Clone, V: AsSlice<T>> SliceConcatExt<T, Vec<T>> for [V] {
|
||||
///
|
||||
/// The last generated swap is always (0, 1), and it returns the
|
||||
/// sequence to its initial order.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[derive(Clone)]
|
||||
pub struct ElementSwaps {
|
||||
sdir: Vec<SizeDirection>,
|
||||
@ -1046,7 +1046,7 @@ pub struct ElementSwaps {
|
||||
|
||||
impl ElementSwaps {
|
||||
/// Creates an `ElementSwaps` iterator for a sequence of `length` elements.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn new(length: uint) -> ElementSwaps {
|
||||
// Initialize `sdir` with a direction that position should move in
|
||||
// (all negative at the beginning) and the `size` of the
|
||||
|
@ -92,7 +92,7 @@ impl String {
|
||||
/// assert_eq!(s.as_slice(), "hello");
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental = "needs investigation to see if to_string() can match perf"]
|
||||
#[unstable = "needs investigation to see if to_string() can match perf"]
|
||||
pub fn from_str(string: &str) -> String {
|
||||
String { vec: ::slice::SliceExt::to_vec(string.as_bytes()) }
|
||||
}
|
||||
@ -719,7 +719,7 @@ impl<'a> FromIterator<&'a str> for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Extend stabilization"]
|
||||
#[unstable = "waiting on Extend stabilization"]
|
||||
impl Extend<char> for String {
|
||||
fn extend<I:Iterator<Item=char>>(&mut self, mut iterator: I) {
|
||||
let (lower_bound, _) = iterator.size_hint();
|
||||
@ -730,7 +730,7 @@ impl Extend<char> for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Extend stabilization"]
|
||||
#[unstable = "waiting on Extend stabilization"]
|
||||
impl<'a> Extend<&'a str> for String {
|
||||
fn extend<I: Iterator<Item=&'a str>>(&mut self, mut iterator: I) {
|
||||
// A guess that at least one byte per iterator element will be needed.
|
||||
@ -790,7 +790,7 @@ impl<'a, 'b> PartialEq<CowString<'a>> for &'b str {
|
||||
fn ne(&self, other: &CowString<'a>) -> bool { PartialEq::ne(&**self, &**other) }
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Str stabilization"]
|
||||
#[unstable = "waiting on Str stabilization"]
|
||||
impl Str for String {
|
||||
#[inline]
|
||||
#[stable]
|
||||
@ -814,14 +814,14 @@ impl fmt::String for String {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on fmt stabilization"]
|
||||
#[unstable = "waiting on fmt stabilization"]
|
||||
impl fmt::Show for String {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Hash stabilization"]
|
||||
#[unstable = "waiting on Hash stabilization"]
|
||||
#[cfg(stage0)]
|
||||
impl<H: hash::Writer> hash::Hash<H> for String {
|
||||
#[inline]
|
||||
@ -829,7 +829,7 @@ impl<H: hash::Writer> hash::Hash<H> for String {
|
||||
(**self).hash(hasher)
|
||||
}
|
||||
}
|
||||
#[experimental = "waiting on Hash stabilization"]
|
||||
#[unstable = "waiting on Hash stabilization"]
|
||||
#[cfg(not(stage0))]
|
||||
impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for String {
|
||||
#[inline]
|
||||
@ -887,7 +887,7 @@ impl ops::Deref for String {
|
||||
}
|
||||
|
||||
/// Wrapper type providing a `&String` reference via `Deref`.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub struct DerefString<'a> {
|
||||
x: DerefVec<'a, u8>
|
||||
}
|
||||
@ -914,7 +914,7 @@ impl<'a> Deref for DerefString<'a> {
|
||||
/// let string = as_string("foo").clone();
|
||||
/// string_consumer(string);
|
||||
/// ```
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {
|
||||
DerefString { x: as_vec(x.as_bytes()) }
|
||||
}
|
||||
|
@ -376,7 +376,7 @@ impl<T> Vec<T> {
|
||||
/// Note that this will drop any excess capacity. Calling this and
|
||||
/// converting back to a vector with `into_vec()` is equivalent to calling
|
||||
/// `shrink_to_fit()`.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn into_boxed_slice(mut self) -> Box<[T]> {
|
||||
self.shrink_to_fit();
|
||||
unsafe {
|
||||
@ -777,7 +777,7 @@ impl<T> Vec<T> {
|
||||
/// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x));
|
||||
/// assert_eq!(newtyped_bytes.as_slice(), [Newtype(0x11), Newtype(0x22)].as_slice());
|
||||
/// ```
|
||||
#[experimental = "API may change to provide stronger guarantees"]
|
||||
#[unstable = "API may change to provide stronger guarantees"]
|
||||
pub fn map_in_place<U, F>(self, mut f: F) -> Vec<U> where F: FnMut(T) -> U {
|
||||
// FIXME: Assert statically that the types `T` and `U` have the same
|
||||
// size.
|
||||
@ -995,7 +995,7 @@ impl<T: Clone> Vec<T> {
|
||||
/// assert_eq!(vec, vec![1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental = "likely to be replaced by a more optimized extend"]
|
||||
#[unstable = "likely to be replaced by a more optimized extend"]
|
||||
pub fn push_all(&mut self, other: &[T]) {
|
||||
self.reserve(other.len());
|
||||
|
||||
@ -1200,7 +1200,7 @@ impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Index stability"]
|
||||
#[unstable = "waiting on Index stability"]
|
||||
impl<T> Index<uint> for Vec<T> {
|
||||
type Output = T;
|
||||
|
||||
@ -1304,7 +1304,7 @@ impl<T> FromIterator<T> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Extend stability"]
|
||||
#[unstable = "waiting on Extend stability"]
|
||||
impl<T> Extend<T> for Vec<T> {
|
||||
#[inline]
|
||||
fn extend<I: Iterator<Item=T>>(&mut self, mut iterator: I) {
|
||||
@ -1457,7 +1457,7 @@ impl<T> Default for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Show stability"]
|
||||
#[unstable = "waiting on Show stability"]
|
||||
impl<T: fmt::Show> fmt::Show for Vec<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Show::fmt(self.as_slice(), f)
|
||||
@ -1475,7 +1475,7 @@ impl<'a> fmt::Writer for Vec<u8> {
|
||||
// Clone-on-write
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[experimental = "unclear how valuable this alias is"]
|
||||
#[unstable = "unclear how valuable this alias is"]
|
||||
/// A clone-on-write vector
|
||||
pub type CowVec<'a, T> = Cow<'a, Vec<T>, [T]>;
|
||||
|
||||
@ -1693,13 +1693,13 @@ impl<'a, T> Drop for Drain<'a, T> {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Wrapper type providing a `&Vec<T>` reference via `Deref`.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub struct DerefVec<'a, T> {
|
||||
x: Vec<T>,
|
||||
l: ContravariantLifetime<'a>
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> Deref for DerefVec<'a, T> {
|
||||
type Target = Vec<T>;
|
||||
|
||||
@ -1719,7 +1719,7 @@ impl<'a, T> Drop for DerefVec<'a, T> {
|
||||
}
|
||||
|
||||
/// Convert a slice to a wrapper type providing a `&Vec<T>` reference.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
|
||||
unsafe {
|
||||
DerefVec {
|
||||
|
@ -89,7 +89,7 @@ use intrinsics::TypeId;
|
||||
#[stable]
|
||||
pub trait Any: 'static {
|
||||
/// Get the `TypeId` of `self`
|
||||
#[experimental = "this method will likely be replaced by an associated static"]
|
||||
#[unstable = "this method will likely be replaced by an associated static"]
|
||||
fn get_type_id(&self) -> TypeId;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
//! up to a certain length. Eventually we should able to generalize
|
||||
//! to all lengths.
|
||||
|
||||
#![experimental] // not yet reviewed
|
||||
#![unstable] // not yet reviewed
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
|
||||
|
@ -202,7 +202,7 @@ impl<T:Copy> Cell<T> {
|
||||
///
|
||||
/// This function is `unsafe` because `UnsafeCell`'s field is public.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
|
||||
&self.value
|
||||
}
|
||||
@ -332,7 +332,7 @@ impl<T> RefCell<T> {
|
||||
///
|
||||
/// This function is `unsafe` because `UnsafeCell`'s field is public.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
|
||||
&self.value
|
||||
}
|
||||
@ -424,7 +424,7 @@ impl<'b, T> Deref for Ref<'b, T> {
|
||||
///
|
||||
/// A `Clone` implementation would interfere with the widespread
|
||||
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
|
||||
#[experimental = "likely to be moved to a method, pending language changes"]
|
||||
#[unstable = "likely to be moved to a method, pending language changes"]
|
||||
pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> {
|
||||
Ref {
|
||||
_value: orig._value,
|
||||
|
@ -81,7 +81,7 @@ clone_impl! { char }
|
||||
|
||||
macro_rules! extern_fn_clone {
|
||||
($($A:ident),*) => (
|
||||
#[experimental = "this may not be sufficient for fns with region parameters"]
|
||||
#[unstable = "this may not be sufficient for fns with region parameters"]
|
||||
impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType {
|
||||
/// Return a copy of a function pointer
|
||||
#[inline]
|
||||
|
@ -290,7 +290,7 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
|
||||
///
|
||||
/// Returns the first argument if the comparison determines them to be equal.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
match v1.partial_cmp(&v2) {
|
||||
Some(Less) | Some(Equal) => Some(v1),
|
||||
@ -303,7 +303,7 @@ pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
///
|
||||
/// Returns the first argument if the comparison determines them to be equal.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
|
||||
match v1.partial_cmp(&v2) {
|
||||
Some(Less) => Some(v2),
|
||||
|
@ -32,7 +32,7 @@
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
|
||||
use ops::{Drop, FnMut, FnOnce};
|
||||
|
||||
|
@ -36,7 +36,7 @@ mod num;
|
||||
mod float;
|
||||
pub mod rt;
|
||||
|
||||
#[experimental = "core and I/O reconciliation may alter this definition"]
|
||||
#[unstable = "core and I/O reconciliation may alter this definition"]
|
||||
/// The type returned by formatter methods.
|
||||
pub type Result = result::Result<(), Error>;
|
||||
|
||||
@ -45,7 +45,7 @@ pub type Result = result::Result<(), Error>;
|
||||
/// This type does not support transmission of an error other than that an error
|
||||
/// occurred. Any extra information must be arranged to be transmitted through
|
||||
/// some other means.
|
||||
#[experimental = "core and I/O reconciliation may alter this definition"]
|
||||
#[unstable = "core and I/O reconciliation may alter this definition"]
|
||||
#[derive(Copy)]
|
||||
pub struct Error;
|
||||
|
||||
@ -58,7 +58,7 @@ pub struct Error;
|
||||
/// This trait should generally not be implemented by consumers of the standard
|
||||
/// library. The `write!` macro accepts an instance of `io::Writer`, and the
|
||||
/// `io::Writer` trait is favored over implementing this trait.
|
||||
#[experimental = "waiting for core and I/O reconciliation"]
|
||||
#[unstable = "waiting for core and I/O reconciliation"]
|
||||
pub trait Writer {
|
||||
/// Writes a slice of bytes into this writer, returning whether the write
|
||||
/// succeeded.
|
||||
@ -123,7 +123,7 @@ enum Void {}
|
||||
/// family of functions. It contains a function to format the given value. At
|
||||
/// compile time it is ensured that the function and the value have the correct
|
||||
/// types, and then this struct is used to canonicalize arguments to one type.
|
||||
#[experimental = "implementation detail of the `format_args!` macro"]
|
||||
#[unstable = "implementation detail of the `format_args!` macro"]
|
||||
#[derive(Copy)]
|
||||
pub struct Argument<'a> {
|
||||
value: &'a Void,
|
||||
@ -162,7 +162,7 @@ impl<'a> Arguments<'a> {
|
||||
/// When using the format_args!() macro, this function is used to generate the
|
||||
/// Arguments structure.
|
||||
#[doc(hidden)] #[inline]
|
||||
#[experimental = "implementation detail of the `format_args!` macro"]
|
||||
#[unstable = "implementation detail of the `format_args!` macro"]
|
||||
pub fn new(pieces: &'a [&'a str],
|
||||
args: &'a [Argument<'a>]) -> Arguments<'a> {
|
||||
Arguments {
|
||||
@ -179,7 +179,7 @@ impl<'a> Arguments<'a> {
|
||||
/// created with `argumentuint`. However, failing to do so doesn't cause
|
||||
/// unsafety, but will ignore invalid .
|
||||
#[doc(hidden)] #[inline]
|
||||
#[experimental = "implementation detail of the `format_args!` macro"]
|
||||
#[unstable = "implementation detail of the `format_args!` macro"]
|
||||
pub fn with_placeholders(pieces: &'a [&'a str],
|
||||
fmt: &'a [rt::Argument<'a>],
|
||||
args: &'a [Argument<'a>]) -> Arguments<'a> {
|
||||
@ -301,7 +301,7 @@ pub trait UpperExp {
|
||||
///
|
||||
/// * output - the buffer to write output to
|
||||
/// * args - the precompiled arguments generated by `format_args!`
|
||||
#[experimental = "libcore and I/O have yet to be reconciled, and this is an \
|
||||
#[unstable = "libcore and I/O have yet to be reconciled, and this is an \
|
||||
implementation detail which should not otherwise be exported"]
|
||||
pub fn write(output: &mut Writer, args: Arguments) -> Result {
|
||||
let mut formatter = Formatter {
|
||||
@ -563,7 +563,7 @@ impl<'a> Formatter<'a> {
|
||||
}
|
||||
|
||||
/// Flags for formatting (packed version of rt::Flag)
|
||||
#[experimental = "return type may change and method was just created"]
|
||||
#[unstable = "return type may change and method was just created"]
|
||||
pub fn flags(&self) -> uint { self.flags }
|
||||
|
||||
/// Character used as 'fill' whenever there is alignment
|
||||
@ -592,7 +592,7 @@ impl Show for Error {
|
||||
/// This is a function which calls are emitted to by the compiler itself to
|
||||
/// create the Argument structures that are passed into the `format` function.
|
||||
#[doc(hidden)] #[inline]
|
||||
#[experimental = "implementation detail of the `format_args!` macro"]
|
||||
#[unstable = "implementation detail of the `format_args!` macro"]
|
||||
pub fn argument<'a, T>(f: fn(&T, &mut Formatter) -> Result,
|
||||
t: &'a T) -> Argument<'a> {
|
||||
Argument::new(t, f)
|
||||
@ -601,7 +601,7 @@ pub fn argument<'a, T>(f: fn(&T, &mut Formatter) -> Result,
|
||||
/// When the compiler determines that the type of an argument *must* be a uint
|
||||
/// (such as for width and precision), then it invokes this method.
|
||||
#[doc(hidden)] #[inline]
|
||||
#[experimental = "implementation detail of the `format_args!` macro"]
|
||||
#[unstable = "implementation detail of the `format_args!` macro"]
|
||||
pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
|
||||
Argument::from_uint(s)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
//! These definitions are similar to their `ct` equivalents, but differ in that
|
||||
//! these can be statically allocated and are slightly optimized for the runtime
|
||||
|
||||
#![experimental = "implementation detail of the `format_args!` macro"]
|
||||
#![unstable = "implementation detail of the `format_args!` macro"]
|
||||
|
||||
pub use self::Alignment::*;
|
||||
pub use self::Count::*;
|
||||
|
@ -39,7 +39,7 @@
|
||||
//! guaranteed to happen in order. This is the standard mode for working
|
||||
//! with atomic types and is equivalent to Java's `volatile`.
|
||||
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
@ -333,7 +333,7 @@ extern "rust-intrinsic" {
|
||||
|
||||
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
|
||||
/// bytes of memory starting at `dst` to `c`.
|
||||
#[experimental = "uncertain about naming and semantics"]
|
||||
#[unstable = "uncertain about naming and semantics"]
|
||||
pub fn set_memory<T>(dst: *mut T, val: u8, count: uint);
|
||||
|
||||
/// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
|
||||
|
@ -942,7 +942,7 @@ pub trait IteratorExt: Iterator + Sized {
|
||||
}
|
||||
|
||||
/// Use an iterator to reverse a container in place.
|
||||
#[experimental = "uncertain about placement or widespread use"]
|
||||
#[unstable = "uncertain about placement or widespread use"]
|
||||
fn reverse_in_place<'a, T: 'a>(&mut self) where
|
||||
Self: Iterator<Item=&'a mut T> + DoubleEndedIterator
|
||||
{
|
||||
@ -974,7 +974,7 @@ pub trait DoubleEndedIterator: Iterator {
|
||||
/// Calling `next()` or `next_back()` on a `RandomAccessIterator`
|
||||
/// reduces the indexable range accordingly. That is, `it.idx(1)` will become `it.idx(0)`
|
||||
/// after `it.next()` is called.
|
||||
#[experimental = "not widely used, may be better decomposed into Index and ExactSizeIterator"]
|
||||
#[unstable = "not widely used, may be better decomposed into Index and ExactSizeIterator"]
|
||||
pub trait RandomAccessIterator: Iterator {
|
||||
/// Return the number of indexable elements. At most `std::uint::MAX`
|
||||
/// elements are indexable, even if the iterator represents a longer range.
|
||||
@ -1049,7 +1049,7 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
|
||||
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Rev<I> where I: DoubleEndedIterator + RandomAccessIterator {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint { self.iter.indexable() }
|
||||
@ -1084,7 +1084,7 @@ impl<'a, I> DoubleEndedIterator for ByRef<'a, I> where I: 'a + DoubleEndedIterat
|
||||
}
|
||||
|
||||
/// A trait for iterators over elements which can be added together
|
||||
#[experimental = "needs to be re-evaluated as part of numerics reform"]
|
||||
#[unstable = "needs to be re-evaluated as part of numerics reform"]
|
||||
pub trait AdditiveIterator<A> {
|
||||
/// Iterates over the entire iterator, summing up all the elements
|
||||
///
|
||||
@ -1102,7 +1102,7 @@ pub trait AdditiveIterator<A> {
|
||||
|
||||
macro_rules! impl_additive {
|
||||
($A:ty, $init:expr) => {
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<T: Iterator<Item=$A>> AdditiveIterator<$A> for T {
|
||||
#[inline]
|
||||
fn sum(self) -> $A {
|
||||
@ -1125,7 +1125,7 @@ impl_additive! { f32, 0.0 }
|
||||
impl_additive! { f64, 0.0 }
|
||||
|
||||
/// A trait for iterators over elements which can be multiplied together.
|
||||
#[experimental = "needs to be re-evaluated as part of numerics reform"]
|
||||
#[unstable = "needs to be re-evaluated as part of numerics reform"]
|
||||
pub trait MultiplicativeIterator<A> {
|
||||
/// Iterates over the entire iterator, multiplying all the elements
|
||||
///
|
||||
@ -1146,7 +1146,7 @@ pub trait MultiplicativeIterator<A> {
|
||||
|
||||
macro_rules! impl_multiplicative {
|
||||
($A:ty, $init:expr) => {
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<T: Iterator<Item=$A>> MultiplicativeIterator<$A> for T {
|
||||
#[inline]
|
||||
fn product(self) -> $A {
|
||||
@ -1287,7 +1287,7 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Cycle<I> where
|
||||
I: Clone + RandomAccessIterator,
|
||||
{
|
||||
@ -1372,7 +1372,7 @@ impl<T, A, B> DoubleEndedIterator for Chain<A, B> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<T, A, B> RandomAccessIterator for Chain<A, B> where
|
||||
A: RandomAccessIterator<Item=T>,
|
||||
B: RandomAccessIterator<Item=T>,
|
||||
@ -1464,7 +1464,7 @@ impl<T, U, A, B> DoubleEndedIterator for Zip<A, B> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<T, U, A, B> RandomAccessIterator for Zip<A, B> where
|
||||
A: RandomAccessIterator<Item=T>,
|
||||
B: RandomAccessIterator<Item=U>,
|
||||
@ -1546,7 +1546,7 @@ impl<A, B, I, F> DoubleEndedIterator for Map<A, B, I, F> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<A, B, I, F> RandomAccessIterator for Map<A, B, I, F> where
|
||||
I: RandomAccessIterator<Item=A>,
|
||||
F: FnMut(A) -> B,
|
||||
@ -1735,7 +1735,7 @@ impl<I> DoubleEndedIterator for Enumerate<I> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Enumerate<I> where I: RandomAccessIterator {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -1961,7 +1961,7 @@ impl<I> Iterator for Skip<I> where I: Iterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Skip<I> where I: RandomAccessIterator{
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -2016,7 +2016,7 @@ impl<I> Iterator for Take<I> where I: Iterator{
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Take<I> where I: RandomAccessIterator{
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -2229,7 +2229,7 @@ impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
|
||||
}
|
||||
|
||||
// Allow RandomAccessIterators to be fused without affecting random-access behavior
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<I> RandomAccessIterator for Fuse<I> where I: RandomAccessIterator {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -2246,7 +2246,7 @@ impl<I> Fuse<I> {
|
||||
/// Resets the fuse such that the next call to .next() or .next_back() will
|
||||
/// call the underlying iterator again even if it previously returned None.
|
||||
#[inline]
|
||||
#[experimental = "seems marginal"]
|
||||
#[unstable = "seems marginal"]
|
||||
pub fn reset_fuse(&mut self) {
|
||||
self.done = false
|
||||
}
|
||||
@ -2315,7 +2315,7 @@ impl<A, I, F> DoubleEndedIterator for Inspect<A, I, F> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<A, I, F> RandomAccessIterator for Inspect<A, I, F> where
|
||||
I: RandomAccessIterator<Item=A>,
|
||||
F: FnMut(&A),
|
||||
@ -2364,7 +2364,7 @@ impl<A, I, F> RandomAccessIterator for Inspect<A, I, F> where
|
||||
/// println!("{}", i);
|
||||
/// }
|
||||
/// ```
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub struct Unfold<A, St, F> where F: FnMut(&mut St) -> Option<A> {
|
||||
f: F,
|
||||
/// Internal state that will be passed to the closure on the next iteration
|
||||
@ -2385,7 +2385,7 @@ impl<A, St, F> Clone for Unfold<A, St, F> where
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<A, St, F> Unfold<A, St, F> where F: FnMut(&mut St) -> Option<A> {
|
||||
/// Creates a new iterator with the specified closure as the "iterator
|
||||
/// function" and an initial state to eventually pass to the closure
|
||||
@ -2778,7 +2778,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
|
||||
fn next_back(&mut self) -> Option<A> { self.idx(0) }
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<A: Clone> RandomAccessIterator for Repeat<A> {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint { uint::MAX }
|
||||
@ -2790,12 +2790,12 @@ type IterateState<T, F> = (F, Option<T>, bool);
|
||||
|
||||
/// An iterator that repeatedly applies a given function, starting
|
||||
/// from a given seed value.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub type Iterate<T, F> = Unfold<T, IterateState<T, F>, fn(&mut IterateState<T, F>) -> Option<T>>;
|
||||
|
||||
/// Create a new iterator that produces an infinite sequence of
|
||||
/// repeated applications of the given function `f`.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
|
||||
T: Clone,
|
||||
F: FnMut(T) -> T,
|
||||
|
@ -48,7 +48,7 @@
|
||||
// separate crate, libcoretest, to avoid bizarre issues.
|
||||
|
||||
#![crate_name = "core"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
@ -59,9 +59,10 @@
|
||||
#![no_std]
|
||||
#![allow(unknown_features, raw_pointer_derive)]
|
||||
#![cfg_attr(stage0, allow(unused_attributes))]
|
||||
#![feature(intrinsics, lang_items)]
|
||||
#![allow(unknown_features)] #![feature(intrinsics, lang_items)]
|
||||
#![feature(simd, unsafe_destructor, slicing_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -15,7 +15,7 @@ macro_rules! panic {
|
||||
panic!("explicit panic")
|
||||
);
|
||||
($msg:expr) => ({
|
||||
static _MSG_FILE_LINE: (&'static str, &'static str, uint) = ($msg, file!(), line!());
|
||||
static _MSG_FILE_LINE: (&'static str, &'static str, usize) = ($msg, file!(), line!());
|
||||
::core::panicking::panic(&_MSG_FILE_LINE)
|
||||
});
|
||||
($fmt:expr, $($arg:tt)*) => ({
|
||||
@ -23,7 +23,7 @@ macro_rules! panic {
|
||||
// used inside a dead function. Just `#[allow(dead_code)]` is
|
||||
// insufficient, since the user may have
|
||||
// `#[forbid(dead_code)]` and which cannot be overridden.
|
||||
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
|
||||
static _FILE_LINE: (&'static str, usize) = (file!(), line!());
|
||||
::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
|
||||
});
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ unsafe impl Zeroable for u64 {}
|
||||
/// NULL or 0 that might allow certain optimizations.
|
||||
#[lang="non_zero"]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Show)]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub struct NonZero<T: Zeroable>(T);
|
||||
|
||||
impl<T: Zeroable> NonZero<T> {
|
||||
|
@ -726,7 +726,7 @@ impl UnsignedInt for u32 {}
|
||||
impl UnsignedInt for u64 {}
|
||||
|
||||
/// A generic trait for converting a value to a number.
|
||||
#[experimental = "trait is likely to be removed"]
|
||||
#[unstable = "trait is likely to be removed"]
|
||||
pub trait ToPrimitive {
|
||||
/// Converts the value of `self` to an `int`.
|
||||
#[inline]
|
||||
@ -991,7 +991,7 @@ impl_to_primitive_float! { f32 }
|
||||
impl_to_primitive_float! { f64 }
|
||||
|
||||
/// A generic trait for converting a number to a value.
|
||||
#[experimental = "trait is likely to be removed"]
|
||||
#[unstable = "trait is likely to be removed"]
|
||||
pub trait FromPrimitive : ::marker::Sized {
|
||||
/// Convert an `int` to return an optional value of this type. If the
|
||||
/// value cannot be represented by this value, the `None` is returned.
|
||||
@ -1073,73 +1073,73 @@ pub trait FromPrimitive : ::marker::Sized {
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_int`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_int<A: FromPrimitive>(n: int) -> Option<A> {
|
||||
FromPrimitive::from_int(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_i8`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_i8<A: FromPrimitive>(n: i8) -> Option<A> {
|
||||
FromPrimitive::from_i8(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_i16`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_i16<A: FromPrimitive>(n: i16) -> Option<A> {
|
||||
FromPrimitive::from_i16(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_i32`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_i32<A: FromPrimitive>(n: i32) -> Option<A> {
|
||||
FromPrimitive::from_i32(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_i64`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_i64<A: FromPrimitive>(n: i64) -> Option<A> {
|
||||
FromPrimitive::from_i64(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_uint`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_uint<A: FromPrimitive>(n: uint) -> Option<A> {
|
||||
FromPrimitive::from_uint(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_u8`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_u8<A: FromPrimitive>(n: u8) -> Option<A> {
|
||||
FromPrimitive::from_u8(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_u16`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_u16<A: FromPrimitive>(n: u16) -> Option<A> {
|
||||
FromPrimitive::from_u16(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_u32`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_u32<A: FromPrimitive>(n: u32) -> Option<A> {
|
||||
FromPrimitive::from_u32(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_u64`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_u64<A: FromPrimitive>(n: u64) -> Option<A> {
|
||||
FromPrimitive::from_u64(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_f32`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_f32<A: FromPrimitive>(n: f32) -> Option<A> {
|
||||
FromPrimitive::from_f32(n)
|
||||
}
|
||||
|
||||
/// A utility function that just calls `FromPrimitive::from_f64`.
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn from_f64<A: FromPrimitive>(n: f64) -> Option<A> {
|
||||
FromPrimitive::from_f64(n)
|
||||
}
|
||||
@ -1190,13 +1190,13 @@ impl_from_primitive! { f64, to_f64 }
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
#[experimental = "likely to be removed"]
|
||||
#[unstable = "likely to be removed"]
|
||||
pub fn cast<T: NumCast,U: NumCast>(n: T) -> Option<U> {
|
||||
NumCast::from(n)
|
||||
}
|
||||
|
||||
/// An interface for casting between machine scalars.
|
||||
#[experimental = "trait is likely to be removed"]
|
||||
#[unstable = "trait is likely to be removed"]
|
||||
pub trait NumCast: ToPrimitive {
|
||||
/// Creates a number from another value that can be converted into a primitive via the
|
||||
/// `ToPrimitive` trait.
|
||||
@ -1394,20 +1394,20 @@ pub trait Float
|
||||
}
|
||||
|
||||
/// A generic trait for converting a string with a radix (base) to a value
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
pub trait FromStrRadix {
|
||||
fn from_str_radix(str: &str, radix: uint) -> Option<Self>;
|
||||
}
|
||||
|
||||
/// A utility function that just calls FromStrRadix::from_str_radix.
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
|
||||
FromStrRadix::from_str_radix(str, radix)
|
||||
}
|
||||
|
||||
macro_rules! from_str_radix_float_impl {
|
||||
($T:ty) => {
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
impl FromStr for $T {
|
||||
/// Convert a string in base 10 to a float.
|
||||
/// Accepts an optional decimal exponent.
|
||||
@ -1440,7 +1440,7 @@ macro_rules! from_str_radix_float_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
impl FromStrRadix for $T {
|
||||
/// Convert a string in a given base to a float.
|
||||
///
|
||||
@ -1604,7 +1604,7 @@ from_str_radix_float_impl! { f64 }
|
||||
|
||||
macro_rules! from_str_radix_int_impl {
|
||||
($T:ty) => {
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
impl FromStr for $T {
|
||||
#[inline]
|
||||
fn from_str(src: &str) -> Option<$T> {
|
||||
@ -1612,7 +1612,7 @@ macro_rules! from_str_radix_int_impl {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "might need to return Result"]
|
||||
#[unstable = "might need to return Result"]
|
||||
impl FromStrRadix for $T {
|
||||
fn from_str_radix(src: &str, radix: uint) -> Option<$T> {
|
||||
assert!(radix >= 2 && radix <= 36,
|
||||
|
@ -477,7 +477,7 @@ impl<T> Option<T> {
|
||||
/// assert_eq!(x.ok_or(0i), Err(0i));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Some(v) => Ok(v),
|
||||
@ -498,7 +498,7 @@ impl<T> Option<T> {
|
||||
/// assert_eq!(x.ok_or_else(|| 0i), Err(0i));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
|
||||
match self {
|
||||
Some(v) => Ok(v),
|
||||
|
@ -106,7 +106,7 @@ pub use intrinsics::copy_nonoverlapping_memory;
|
||||
#[unstable]
|
||||
pub use intrinsics::copy_memory;
|
||||
|
||||
#[experimental = "uncertain about naming and semantics"]
|
||||
#[unstable = "uncertain about naming and semantics"]
|
||||
pub use intrinsics::set_memory;
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
|
||||
//! Contains struct definitions for the layout of compiler built-in types.
|
||||
//!
|
||||
|
@ -953,7 +953,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
|
||||
/// If an `Err` is encountered, it is immediately returned.
|
||||
/// Otherwise, the folded value is returned.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn fold<T,
|
||||
V,
|
||||
E,
|
||||
|
@ -19,7 +19,7 @@
|
||||
//! provided beyond this module.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[allow(experimental)];
|
||||
//! #[allow(unstable)];
|
||||
//!
|
||||
//! fn main() {
|
||||
//! use std::simd::f32x4;
|
||||
@ -37,7 +37,7 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
@ -46,26 +46,26 @@ pub struct i8x16(pub i8, pub i8, pub i8, pub i8,
|
||||
pub i8, pub i8, pub i8, pub i8,
|
||||
pub i8, pub i8, pub i8, pub i8);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct i16x8(pub i16, pub i16, pub i16, pub i16,
|
||||
pub i16, pub i16, pub i16, pub i16);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct i64x2(pub i64, pub i64);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
@ -74,32 +74,32 @@ pub struct u8x16(pub u8, pub u8, pub u8, pub u8,
|
||||
pub u8, pub u8, pub u8, pub u8,
|
||||
pub u8, pub u8, pub u8, pub u8);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct u16x8(pub u16, pub u16, pub u16, pub u16,
|
||||
pub u16, pub u16, pub u16, pub u16);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct u64x2(pub u64, pub u64);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
#[simd]
|
||||
#[derive(Copy, Show)]
|
||||
#[repr(C)]
|
||||
|
@ -457,7 +457,7 @@ impl<T> SliceExt for [T] {
|
||||
self.binary_search_by(|p| p.cmp(x))
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn next_permutation(&mut self) -> bool where T: Ord {
|
||||
// These cases only have 1 permutation each, so we can't do anything.
|
||||
if self.len() < 2 { return false; }
|
||||
@ -488,7 +488,7 @@ impl<T> SliceExt for [T] {
|
||||
true
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
fn prev_permutation(&mut self) -> bool where T: Ord {
|
||||
// These cases only have 1 permutation each, so we can't do anything.
|
||||
if self.len() < 2 { return false; }
|
||||
@ -630,25 +630,25 @@ impl<T> ops::IndexMut<ops::FullRange> for [T] {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Data that is viewable as a slice.
|
||||
#[experimental = "will be replaced by slice syntax"]
|
||||
#[unstable = "will be replaced by slice syntax"]
|
||||
pub trait AsSlice<T> {
|
||||
/// Work with `self` as a slice.
|
||||
fn as_slice<'a>(&'a self) -> &'a [T];
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<T> AsSlice<T> for [T] {
|
||||
#[inline(always)]
|
||||
fn as_slice<'a>(&'a self) -> &'a [T] { self }
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a U {
|
||||
#[inline(always)]
|
||||
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<'a, T, U: ?Sized + AsSlice<T>> AsSlice<T> for &'a mut U {
|
||||
#[inline(always)]
|
||||
fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) }
|
||||
@ -754,7 +754,7 @@ pub struct Iter<'a, T: 'a> {
|
||||
marker: marker::ContravariantLifetime<'a>
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::Range<uint>> for Iter<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -763,7 +763,7 @@ impl<'a, T> ops::Index<ops::Range<uint>> for Iter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::RangeTo<uint>> for Iter<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -772,7 +772,7 @@ impl<'a, T> ops::Index<ops::RangeTo<uint>> for Iter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::RangeFrom<uint>> for Iter<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -781,7 +781,7 @@ impl<'a, T> ops::Index<ops::RangeFrom<uint>> for Iter<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::FullRange> for Iter<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -795,7 +795,7 @@ impl<'a, T> Iter<'a, T> {
|
||||
///
|
||||
/// This has the same lifetime as the original slice, and so the
|
||||
/// iterator can continue to be used while this exists.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn as_slice(&self) -> &'a [T] {
|
||||
make_slice!(T => &'a [T]: self.ptr, self.end)
|
||||
}
|
||||
@ -813,7 +813,7 @@ impl<'a, T> Clone for Iter<'a, T> {
|
||||
fn clone(&self) -> Iter<'a, T> { *self }
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<'a, T> RandomAccessIterator for Iter<'a, T> {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -847,7 +847,7 @@ pub struct IterMut<'a, T: 'a> {
|
||||
}
|
||||
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::Range<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -855,7 +855,7 @@ impl<'a, T> ops::Index<ops::Range<uint>> for IterMut<'a, T> {
|
||||
self.index(&ops::FullRange).index(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::RangeTo<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -863,7 +863,7 @@ impl<'a, T> ops::Index<ops::RangeTo<uint>> for IterMut<'a, T> {
|
||||
self.index(&ops::FullRange).index(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::RangeFrom<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -871,7 +871,7 @@ impl<'a, T> ops::Index<ops::RangeFrom<uint>> for IterMut<'a, T> {
|
||||
self.index(&ops::FullRange).index(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::Index<ops::FullRange> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -880,7 +880,7 @@ impl<'a, T> ops::Index<ops::FullRange> for IterMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::IndexMut<ops::Range<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -888,7 +888,7 @@ impl<'a, T> ops::IndexMut<ops::Range<uint>> for IterMut<'a, T> {
|
||||
self.index_mut(&ops::FullRange).index_mut(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::IndexMut<ops::RangeTo<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -896,7 +896,7 @@ impl<'a, T> ops::IndexMut<ops::RangeTo<uint>> for IterMut<'a, T> {
|
||||
self.index_mut(&ops::FullRange).index_mut(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::IndexMut<ops::RangeFrom<uint>> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -904,7 +904,7 @@ impl<'a, T> ops::IndexMut<ops::RangeFrom<uint>> for IterMut<'a, T> {
|
||||
self.index_mut(&ops::FullRange).index_mut(index)
|
||||
}
|
||||
}
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl<'a, T> ops::IndexMut<ops::FullRange> for IterMut<'a, T> {
|
||||
type Output = [T];
|
||||
#[inline]
|
||||
@ -921,7 +921,7 @@ impl<'a, T> IterMut<'a, T> {
|
||||
/// to consume the iterator. Consider using the `Slice` and
|
||||
/// `SliceMut` implementations for obtaining slices with more
|
||||
/// restricted lifetimes that do not consume the iterator.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn into_slice(self) -> &'a mut [T] {
|
||||
make_slice!(T => &'a mut [T]: self.ptr, self.end)
|
||||
}
|
||||
@ -1269,7 +1269,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "trait is experimental"]
|
||||
#[unstable = "trait is experimental"]
|
||||
impl<'a, T> RandomAccessIterator for Chunks<'a, T> {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -1417,7 +1417,7 @@ pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] {
|
||||
//
|
||||
|
||||
/// Operations on `[u8]`.
|
||||
#[experimental = "needs review"]
|
||||
#[unstable = "needs review"]
|
||||
pub mod bytes {
|
||||
use ptr;
|
||||
use slice::SliceExt;
|
||||
@ -1430,7 +1430,7 @@ pub mod bytes {
|
||||
|
||||
impl MutableByteVector for [u8] {
|
||||
#[inline]
|
||||
#[allow(experimental)]
|
||||
#[allow(unstable)]
|
||||
fn set_memory(&mut self, value: u8) {
|
||||
unsafe { ptr::set_memory(self.as_mut_ptr(), value, self.len()) };
|
||||
}
|
||||
@ -1506,7 +1506,7 @@ impl<T: PartialOrd> PartialOrd for [T] {
|
||||
}
|
||||
|
||||
/// Extension methods for slices containing integers.
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub trait IntSliceExt<U, S> {
|
||||
/// Converts the slice to an immutable slice of unsigned integers with the same width.
|
||||
fn as_unsigned<'a>(&'a self) -> &'a [U];
|
||||
@ -1521,7 +1521,7 @@ pub trait IntSliceExt<U, S> {
|
||||
|
||||
macro_rules! impl_int_slice {
|
||||
($u:ty, $s:ty, $t:ty) => {
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
impl IntSliceExt<$u, $s> for [$t] {
|
||||
#[inline]
|
||||
fn as_unsigned(&self) -> &[$u] { unsafe { transmute(self) } }
|
||||
|
@ -114,7 +114,7 @@ fn discard_doesnt_unborrow() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(experimental)]
|
||||
#[allow(unstable)]
|
||||
fn clone_ref_updates_flag() {
|
||||
let x = RefCell::new(0i);
|
||||
{
|
||||
|
@ -11,6 +11,7 @@
|
||||
#![feature(unsafe_destructor, slicing_syntax)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
|
@ -15,8 +15,9 @@
|
||||
//! [mz]: https://code.google.com/p/miniz/
|
||||
|
||||
#![crate_name = "flate"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
|
@ -15,7 +15,7 @@
|
||||
//! generated instead.
|
||||
|
||||
#![crate_name = "fmt_macros"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -25,6 +25,7 @@
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![feature(slicing_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
pub use self::Piece::*;
|
||||
pub use self::Position::*;
|
||||
|
@ -78,7 +78,7 @@
|
||||
//! ```
|
||||
|
||||
#![crate_name = "getopts"]
|
||||
#![experimental = "use the crates.io `getopts` library instead"]
|
||||
#![unstable = "use the crates.io `getopts` library instead"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -87,6 +87,7 @@
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![feature(slicing_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)] #[macro_use] extern crate log;
|
||||
|
@ -265,7 +265,7 @@
|
||||
//! * [DOT language](http://www.graphviz.org/doc/info/lang.html)
|
||||
|
||||
#![crate_name = "graphviz"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -273,6 +273,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/")]
|
||||
#![feature(slicing_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
use self::LabelText::*;
|
||||
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
#![crate_name = "libc"]
|
||||
#![crate_type = "rlib"]
|
||||
#![cfg_attr(not(feature = "cargo-build"), experimental)]
|
||||
#![cfg_attr(not(feature = "cargo-build"), unstable)]
|
||||
#![cfg_attr(not(feature = "cargo-build"), staged_api)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![no_std]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
|
@ -156,7 +156,7 @@
|
||||
//! if logging is disabled, none of the components of the log will be executed.
|
||||
|
||||
#![crate_name = "log"]
|
||||
#![experimental = "use the crates.io `log` library instead"]
|
||||
#![unstable = "use the crates.io `log` library instead"]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -168,6 +168,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![feature(slicing_syntax)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
extern crate regex;
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! internally. The `IndependentSample` trait is for generating values
|
||||
//! that do not need to record state.
|
||||
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
|
||||
use core::prelude::*;
|
||||
use core::num::{Float, Int};
|
||||
|
@ -22,9 +22,9 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![no_std]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -16,7 +16,7 @@
|
||||
//! http://www.matroska.org/technical/specs/rfc/index.html
|
||||
|
||||
#![crate_name = "rbml"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
@ -26,6 +26,7 @@
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![allow(unknown_features)]
|
||||
#![feature(slicing_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
|
||||
extern crate serialize;
|
||||
#[macro_use] extern crate log;
|
||||
|
@ -16,7 +16,7 @@
|
||||
#![crate_name = "regex"]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![experimental = "use the crates.io `regex` library instead"]
|
||||
#![unstable = "use the crates.io `regex` library instead"]
|
||||
#![staged_api]
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
@ -26,6 +26,7 @@
|
||||
#![allow(unknown_features)]
|
||||
#![feature(slicing_syntax)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -255,7 +255,7 @@ impl Regex {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[experimental]
|
||||
#[unstable]
|
||||
pub fn names_iter<'a>(&'a self) -> NamesIter<'a> {
|
||||
match *self {
|
||||
Native(ref n) => NamesIterNative(n.names.iter()),
|
||||
@ -410,7 +410,7 @@ pub struct Captures<'t> {
|
||||
}
|
||||
|
||||
impl<'t> Captures<'t> {
|
||||
#[allow(experimental)]
|
||||
#[allow(unstable)]
|
||||
fn new(re: &Regex, search: &'t str, locs: CaptureLocs)
|
||||
-> Option<Captures<'t>> {
|
||||
if !has_match(&locs) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
//! This API is completely unstable and subject to change.
|
||||
|
||||
#![crate_name = "rustc"]
|
||||
#![experimental]
|
||||
#![unstable]
|
||||
#![staged_api]
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
@ -27,8 +27,8 @@
|
||||
#![feature(quote)]
|
||||
#![feature(slicing_syntax, unsafe_destructor)]
|
||||
#![feature(box_syntax)]
|
||||
#![allow(unknown_features)] #![feature(int_uint)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
#![feature(old_impl_check)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate flate;
|
||||
|
@ -216,7 +216,7 @@ impl LintPass for TypeLimits {
|
||||
match lit.node {
|
||||
ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
|
||||
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
|
||||
let int_type = if t == ast::TyIs {
|
||||
let int_type = if let ast::TyIs(_) = t {
|
||||
cx.sess().target.int_type
|
||||
} else { t };
|
||||
let (min, max) = int_ty_range(int_type);
|
||||
@ -233,7 +233,7 @@ impl LintPass for TypeLimits {
|
||||
};
|
||||
},
|
||||
ty::ty_uint(t) => {
|
||||
let uint_type = if t == ast::TyUs {
|
||||
let uint_type = if let ast::TyUs(_) = t {
|
||||
cx.sess().target.uint_type
|
||||
} else { t };
|
||||
let (min, max) = uint_ty_range(uint_type);
|
||||
@ -296,7 +296,7 @@ impl LintPass for TypeLimits {
|
||||
// warnings are consistent between 32- and 64-bit platforms
|
||||
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
|
||||
match int_ty {
|
||||
ast::TyIs=> (i64::MIN, i64::MAX),
|
||||
ast::TyIs(_) => (i64::MIN, i64::MAX),
|
||||
ast::TyI8 => (i8::MIN as i64, i8::MAX as i64),
|
||||
ast::TyI16 => (i16::MIN as i64, i16::MAX as i64),
|
||||
ast::TyI32 => (i32::MIN as i64, i32::MAX as i64),
|
||||
@ -306,7 +306,7 @@ impl LintPass for TypeLimits {
|
||||
|
||||
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
|
||||
match uint_ty {
|
||||
ast::TyUs=> (u64::MIN, u64::MAX),
|
||||
ast::TyUs(_) => (u64::MIN, u64::MAX),
|
||||
ast::TyU8 => (u8::MIN as u64, u8::MAX as u64),
|
||||
ast::TyU16 => (u16::MIN as u64, u16::MAX as u64),
|
||||
ast::TyU32 => (u32::MIN as u64, u32::MAX as u64),
|
||||
@ -323,7 +323,7 @@ impl LintPass for TypeLimits {
|
||||
|
||||
fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
|
||||
match int_ty {
|
||||
ast::TyIs=> int_ty_bits(target_int_ty, target_int_ty),
|
||||
ast::TyIs(_) => int_ty_bits(target_int_ty, target_int_ty),
|
||||
ast::TyI8 => i8::BITS as u64,
|
||||
ast::TyI16 => i16::BITS as u64,
|
||||
ast::TyI32 => i32::BITS as u64,
|
||||
@ -333,7 +333,7 @@ impl LintPass for TypeLimits {
|
||||
|
||||
fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
|
||||
match uint_ty {
|
||||
ast::TyUs=> uint_ty_bits(target_uint_ty, target_uint_ty),
|
||||
ast::TyUs(_) => uint_ty_bits(target_uint_ty, target_uint_ty),
|
||||
ast::TyU8 => u8::BITS as u64,
|
||||
ast::TyU16 => u16::BITS as u64,
|
||||
ast::TyU32 => u32::BITS as u64,
|
||||
@ -404,12 +404,12 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
|
||||
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||
fn check_def(&mut self, sp: Span, ty_id: ast::NodeId, path_id: ast::NodeId) {
|
||||
match self.cx.tcx.def_map.borrow()[path_id].clone() {
|
||||
def::DefPrimTy(ast::TyInt(ast::TyIs)) => {
|
||||
def::DefPrimTy(ast::TyInt(ast::TyIs(_))) => {
|
||||
self.cx.span_lint(IMPROPER_CTYPES, sp,
|
||||
"found rust type `isize` in foreign module, while \
|
||||
libc::c_int or libc::c_long should be used");
|
||||
}
|
||||
def::DefPrimTy(ast::TyUint(ast::TyUs)) => {
|
||||
def::DefPrimTy(ast::TyUint(ast::TyUs(_))) => {
|
||||
self.cx.span_lint(IMPROPER_CTYPES, sp,
|
||||
"found rust type `usize` in foreign module, while \
|
||||
libc::c_uint or libc::c_ulong should be used");
|
||||
@ -1630,36 +1630,29 @@ declare_lint! {
|
||||
Warn,
|
||||
"detects use of #[deprecated] items"
|
||||
}
|
||||
// FIXME #6875: Change to Warn after std library stabilization is complete
|
||||
declare_lint! {
|
||||
EXPERIMENTAL,
|
||||
Allow,
|
||||
"detects use of #[experimental] items"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
UNSTABLE,
|
||||
Allow,
|
||||
Warn,
|
||||
"detects use of #[unstable] items (incl. items with no stability attribute)"
|
||||
}
|
||||
|
||||
declare_lint!(STAGED_EXPERIMENTAL, Warn,
|
||||
"detects use of #[experimental] items in staged builds");
|
||||
|
||||
declare_lint!(STAGED_UNSTABLE, Warn,
|
||||
"detects use of #[unstable] items (incl. items with no stability attribute) \
|
||||
in staged builds");
|
||||
|
||||
/// Checks for use of items with `#[deprecated]`, `#[experimental]` and
|
||||
/// Checks for use of items with `#[deprecated]`, `#[unstable]` and
|
||||
/// `#[unstable]` attributes, or no stability attribute.
|
||||
#[derive(Copy)]
|
||||
pub struct Stability;
|
||||
pub struct Stability { this_crate_staged: bool }
|
||||
|
||||
impl Stability {
|
||||
pub fn new() -> Stability { Stability { this_crate_staged: false } }
|
||||
|
||||
fn lint(&self, cx: &Context, id: ast::DefId, span: Span) {
|
||||
|
||||
let ref stability = stability::lookup(cx.tcx, id);
|
||||
let cross_crate = !ast_util::is_local(id);
|
||||
let staged = (!cross_crate && self.this_crate_staged)
|
||||
|| (cross_crate && stability::is_staged_api(cx.tcx, id));
|
||||
|
||||
if !staged { return }
|
||||
|
||||
// stability attributes are promises made across crates; only
|
||||
// check DEPRECATED for crate-local usage.
|
||||
@ -1668,21 +1661,12 @@ impl Stability {
|
||||
None if cross_crate => (UNSTABLE, "unmarked"),
|
||||
Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate =>
|
||||
(UNSTABLE, "unstable"),
|
||||
Some(attr::Stability { level: attr::Experimental, .. }) if cross_crate =>
|
||||
(EXPERIMENTAL, "experimental"),
|
||||
Some(attr::Stability { level: attr::Deprecated, .. }) =>
|
||||
(DEPRECATED, "deprecated"),
|
||||
_ => return
|
||||
};
|
||||
|
||||
output(cx, span, stability, lint, label);
|
||||
if cross_crate && stability::is_staged_api(cx.tcx, id) {
|
||||
if lint.name == UNSTABLE.name {
|
||||
output(cx, span, stability, STAGED_UNSTABLE, label);
|
||||
} else if lint.name == EXPERIMENTAL.name {
|
||||
output(cx, span, stability, STAGED_EXPERIMENTAL, label);
|
||||
}
|
||||
}
|
||||
|
||||
fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>,
|
||||
lint: &'static Lint, label: &'static str) {
|
||||
@ -1706,7 +1690,7 @@ impl Stability {
|
||||
|
||||
impl LintPass for Stability {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE, STAGED_EXPERIMENTAL, STAGED_UNSTABLE)
|
||||
lint_array!(DEPRECATED, UNSTABLE)
|
||||
}
|
||||
|
||||
fn check_crate(&mut self, _: &Context, c: &ast::Crate) {
|
||||
@ -1717,6 +1701,7 @@ impl LintPass for Stability {
|
||||
match attr.node.value.node {
|
||||
ast::MetaWord(_) => {
|
||||
attr::mark_used(attr);
|
||||
self.this_crate_staged = true;
|
||||
}
|
||||
_ => (/*pass*/)
|
||||
}
|
||||
|
@ -209,7 +209,6 @@ impl LintStore {
|
||||
UnsafeBlocks,
|
||||
UnusedMut,
|
||||
UnusedAllocation,
|
||||
Stability,
|
||||
MissingCopyImplementations,
|
||||
UnstableFeatures,
|
||||
);
|
||||
@ -218,6 +217,7 @@ impl LintStore {
|
||||
TypeLimits,
|
||||
RawPointerDerive,
|
||||
MissingDoc,
|
||||
Stability,
|
||||
);
|
||||
|
||||
add_lint_group!(sess, "bad_style",
|
||||
@ -308,18 +308,21 @@ impl LintStore {
|
||||
UnstableFeatures::Cheat => Allow
|
||||
};
|
||||
match self.by_name.get("unstable_features") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
||||
self.set_level(lint_id, (lvl, ReleaseChannel))
|
||||
},
|
||||
Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
||||
self.set_level(lint_id, (lvl, ReleaseChannel))
|
||||
},
|
||||
None => unreachable!()
|
||||
}
|
||||
match self.by_name.get("staged_unstable") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
None => unreachable!()
|
||||
}
|
||||
match self.by_name.get("staged_experimental") {
|
||||
Some(&Id(lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
Some(&Renamed(_, lint_id)) => self.set_level(lint_id, (lvl, ReleaseChannel)),
|
||||
match self.by_name.get("unstable") {
|
||||
Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
||||
self.set_level(lint_id, (lvl, ReleaseChannel))
|
||||
},
|
||||
Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
||||
self.set_level(lint_id, (lvl, ReleaseChannel))
|
||||
},
|
||||
None => unreachable!()
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ use syntax::ast;
|
||||
pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs};
|
||||
|
||||
/// Specification of a single lint.
|
||||
#[derive(Copy)]
|
||||
#[derive(Copy, Show)]
|
||||
pub struct Lint {
|
||||
/// A string identifier for the lint.
|
||||
///
|
||||
@ -208,7 +208,7 @@ impl LintId {
|
||||
}
|
||||
|
||||
/// Setting for how to handle a lint.
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Show)]
|
||||
pub enum Level {
|
||||
Allow, Warn, Deny, Forbid
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
||||
ty::ty_char => mywrite!(w, "c"),
|
||||
ty::ty_int(t) => {
|
||||
match t {
|
||||
ast::TyIs => mywrite!(w, "is"),
|
||||
ast::TyIs(_) => mywrite!(w, "is"),
|
||||
ast::TyI8 => mywrite!(w, "MB"),
|
||||
ast::TyI16 => mywrite!(w, "MW"),
|
||||
ast::TyI32 => mywrite!(w, "ML"),
|
||||
@ -70,7 +70,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
|
||||
}
|
||||
ty::ty_uint(t) => {
|
||||
match t {
|
||||
ast::TyUs => mywrite!(w, "us"),
|
||||
ast::TyUs(_) => mywrite!(w, "us"),
|
||||
ast::TyU8 => mywrite!(w, "Mb"),
|
||||
ast::TyU16 => mywrite!(w, "Mw"),
|
||||
ast::TyU32 => mywrite!(w, "Ml"),
|
||||
|
@ -528,12 +528,12 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St
|
||||
|
||||
eval_const_expr_partial(tcx, &**base)
|
||||
.and_then(|val| define_casts!(val, {
|
||||
ty::ty_int(ast::TyIs) => (int, const_int, i64),
|
||||
ty::ty_int(ast::TyIs(_)) => (int, const_int, i64),
|
||||
ty::ty_int(ast::TyI8) => (i8, const_int, i64),
|
||||
ty::ty_int(ast::TyI16) => (i16, const_int, i64),
|
||||
ty::ty_int(ast::TyI32) => (i32, const_int, i64),
|
||||
ty::ty_int(ast::TyI64) => (i64, const_int, i64),
|
||||
ty::ty_uint(ast::TyUs) => (uint, const_uint, u64),
|
||||
ty::ty_uint(ast::TyUs(_)) => (uint, const_uint, u64),
|
||||
ty::ty_uint(ast::TyU8) => (u8, const_uint, u64),
|
||||
ty::ty_uint(ast::TyU16) => (u16, const_uint, u64),
|
||||
ty::ty_uint(ast::TyU32) => (u32, const_uint, u64),
|
||||
|
@ -75,7 +75,7 @@ use middle::def;
|
||||
use middle::region;
|
||||
use middle::ty::{self, Ty};
|
||||
use util::nodemap::{NodeMap};
|
||||
use util::ppaux::{Repr};
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
use syntax::ast::{MutImmutable, MutMutable};
|
||||
use syntax::ast;
|
||||
@ -113,10 +113,17 @@ pub struct Upvar {
|
||||
// different kinds of pointers:
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Show)]
|
||||
pub enum PointerKind {
|
||||
/// `Box<T>`
|
||||
Unique,
|
||||
|
||||
/// `&T`
|
||||
BorrowedPtr(ty::BorrowKind, ty::Region),
|
||||
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
|
||||
UnsafePtr(ast::Mutability)
|
||||
|
||||
/// `*T`
|
||||
UnsafePtr(ast::Mutability),
|
||||
|
||||
/// Implicit deref of the `&T` that results from an overloaded index `[]`.
|
||||
Implicit(ty::BorrowKind, ty::Region),
|
||||
}
|
||||
|
||||
// We use the term "interior" to mean "something reachable from the
|
||||
@ -453,7 +460,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
autoderefs,
|
||||
cmt.repr(self.tcx()));
|
||||
for deref in range(1u, autoderefs + 1) {
|
||||
cmt = try!(self.cat_deref(expr, cmt, deref, false));
|
||||
cmt = try!(self.cat_deref(expr, cmt, deref));
|
||||
}
|
||||
return Ok(cmt);
|
||||
}
|
||||
@ -465,7 +472,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
match expr.node {
|
||||
ast::ExprUnary(ast::UnDeref, ref e_base) => {
|
||||
let base_cmt = try!(self.cat_expr(&**e_base));
|
||||
self.cat_deref(expr, base_cmt, 0, false)
|
||||
self.cat_deref(expr, base_cmt, 0)
|
||||
}
|
||||
|
||||
ast::ExprField(ref base, f_name) => {
|
||||
@ -489,10 +496,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
// If this is an index implemented by a method call, then it
|
||||
// will include an implicit deref of the result.
|
||||
let ret_ty = self.overloaded_method_return_ty(method_ty);
|
||||
self.cat_deref(expr,
|
||||
self.cat_rvalue_node(expr.id(),
|
||||
expr.span(),
|
||||
ret_ty), 1, true)
|
||||
|
||||
// The index method always returns an `&T`, so
|
||||
// dereference it to find the result type.
|
||||
let elem_ty = match ret_ty.sty {
|
||||
ty::ty_rptr(_, mt) => mt.ty,
|
||||
_ => {
|
||||
debug!("cat_expr_unadjusted: return type of overloaded index is {}?",
|
||||
ret_ty.repr(self.tcx()));
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
// The call to index() returns a `&T` value, which
|
||||
// is an rvalue. That is what we will be
|
||||
// dereferencing.
|
||||
let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
|
||||
self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)
|
||||
}
|
||||
None => {
|
||||
self.cat_index(expr, try!(self.cat_expr(&**base)))
|
||||
@ -837,8 +857,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
fn cat_deref<N:ast_node>(&self,
|
||||
node: &N,
|
||||
base_cmt: cmt<'tcx>,
|
||||
deref_cnt: uint,
|
||||
implicit: bool)
|
||||
deref_cnt: uint)
|
||||
-> McResult<cmt<'tcx>> {
|
||||
let adjustment = match self.typer.adjustments().borrow().get(&node.id()) {
|
||||
Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject,
|
||||
@ -866,7 +885,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
};
|
||||
let base_cmt_ty = base_cmt.ty;
|
||||
match ty::deref(base_cmt_ty, true) {
|
||||
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
|
||||
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty,
|
||||
/* implicit: */ false),
|
||||
None => {
|
||||
debug!("Explicit deref of non-derefable type: {}",
|
||||
base_cmt_ty.repr(self.tcx()));
|
||||
@ -1236,7 +1256,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||
// PatRegion since that information is already contained
|
||||
// in the type.
|
||||
let subcmt = try!(self.cat_deref(pat, cmt, 0, false));
|
||||
let subcmt = try!(self.cat_deref(pat, cmt, 0));
|
||||
try!(self.cat_pattern_(subcmt, &**subpat, op));
|
||||
}
|
||||
|
||||
@ -1392,22 +1412,6 @@ impl<'tcx> cmt_<'tcx> {
|
||||
|
||||
|
||||
pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
|
||||
fn upvar_to_string(upvar: &Upvar, is_copy: bool) -> String {
|
||||
if upvar.is_unboxed {
|
||||
let kind = match upvar.kind {
|
||||
ty::FnUnboxedClosureKind => "Fn",
|
||||
ty::FnMutUnboxedClosureKind => "FnMut",
|
||||
ty::FnOnceUnboxedClosureKind => "FnOnce"
|
||||
};
|
||||
format!("captured outer variable in an `{}` closure", kind)
|
||||
} else {
|
||||
(match (upvar.kind, is_copy) {
|
||||
(ty::FnOnceUnboxedClosureKind, true) => "captured outer variable in a proc",
|
||||
_ => "captured outer variable"
|
||||
}).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
match self.cat {
|
||||
cat_static_item => {
|
||||
"static item".to_string()
|
||||
@ -1427,16 +1431,23 @@ impl<'tcx> cmt_<'tcx> {
|
||||
let upvar = self.upvar();
|
||||
match upvar.as_ref().map(|i| &i.cat) {
|
||||
Some(&cat_upvar(ref var)) => {
|
||||
upvar_to_string(var, false)
|
||||
var.user_string(tcx)
|
||||
}
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
match pk {
|
||||
Implicit(..) => {
|
||||
"dereference (dereference is implicit, due to indexing)".to_string()
|
||||
format!("indexed content")
|
||||
}
|
||||
Unique => {
|
||||
format!("`Box` content")
|
||||
}
|
||||
UnsafePtr(..) => {
|
||||
format!("dereference of unsafe pointer")
|
||||
}
|
||||
BorrowedPtr(..) => {
|
||||
format!("borrowed content")
|
||||
}
|
||||
Unique => format!("dereference of `{}`", ptr_sigil(pk)),
|
||||
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1447,14 +1458,12 @@ impl<'tcx> cmt_<'tcx> {
|
||||
cat_interior(_, InteriorField(PositionalField(_))) => {
|
||||
"anonymous field".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(VecElement)) => {
|
||||
"vec content".to_string()
|
||||
}
|
||||
cat_interior(_, InteriorElement(VecElement)) |
|
||||
cat_interior(_, InteriorElement(OtherElement)) => {
|
||||
"indexed content".to_string()
|
||||
}
|
||||
cat_upvar(ref var) => {
|
||||
upvar_to_string(var, true)
|
||||
var.user_string(tcx)
|
||||
}
|
||||
cat_downcast(ref cmt, _) => {
|
||||
cmt.descriptive_string(tcx)
|
||||
@ -1483,7 +1492,7 @@ impl<'tcx> Repr<'tcx> for categorization<'tcx> {
|
||||
format!("{:?}", *self)
|
||||
}
|
||||
cat_deref(ref cmt, derefs, ptr) => {
|
||||
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr_sigil(ptr), derefs)
|
||||
format!("{}-{}{}->", cmt.cat.repr(tcx), ptr.repr(tcx), derefs)
|
||||
}
|
||||
cat_interior(ref cmt, interior) => {
|
||||
format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
|
||||
@ -1504,7 +1513,32 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
|
||||
Implicit(ty::MutBorrow, _) => "&mut",
|
||||
BorrowedPtr(ty::UniqueImmBorrow, _) |
|
||||
Implicit(ty::UniqueImmBorrow, _) => "&unique",
|
||||
UnsafePtr(_) => "*"
|
||||
UnsafePtr(_) => "*",
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for PointerKind {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
match *self {
|
||||
Unique => {
|
||||
format!("Box")
|
||||
}
|
||||
BorrowedPtr(ty::ImmBorrow, ref r) |
|
||||
Implicit(ty::ImmBorrow, ref r) => {
|
||||
format!("&{}", r.repr(tcx))
|
||||
}
|
||||
BorrowedPtr(ty::MutBorrow, ref r) |
|
||||
Implicit(ty::MutBorrow, ref r) => {
|
||||
format!("&{} mut", r.repr(tcx))
|
||||
}
|
||||
BorrowedPtr(ty::UniqueImmBorrow, ref r) |
|
||||
Implicit(ty::UniqueImmBorrow, ref r) => {
|
||||
format!("&{} uniq", r.repr(tcx))
|
||||
}
|
||||
UnsafePtr(_) => {
|
||||
format!("*")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1531,3 +1565,27 @@ fn element_kind(t: Ty) -> ElementKind {
|
||||
_ => OtherElement
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::UnboxedClosureKind {
|
||||
fn repr(&self, _: &ty::ctxt) -> String {
|
||||
format!("Upvar({:?})", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for Upvar {
|
||||
fn repr(&self, tcx: &ty::ctxt) -> String {
|
||||
format!("Upvar({})", self.kind.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UserString<'tcx> for Upvar {
|
||||
fn user_string(&self, _: &ty::ctxt) -> String {
|
||||
let kind = match self.kind {
|
||||
ty::FnUnboxedClosureKind => "Fn",
|
||||
ty::FnMutUnboxedClosureKind => "FnMut",
|
||||
ty::FnOnceUnboxedClosureKind => "FnOnce",
|
||||
};
|
||||
format!("captured outer variable in an `{}` closure", kind)
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user