let x; // declare "x"
x = 42; // assign 42 to "x"
let x = 42; // combined in one line
let x: i32; // `i32` is a signed 32-bit integer
x = 42;
// there's i8, i16, i32, i64, i128
// also u8, u16, u32, u64, u128 for unsigned
let x: i32 = 42; // combined in one line
let x;
foobar(x); // error: borrow of possibly-uninitialized variable: `x`
x = 42;
let x;
x = 42;
foobar(x); // the type of `x` will be inferred from here
// this does *nothing* because 42 is a constant
let _ = 42;
// this calls `get_thing` but throws away its result
let _ = get_thing();
// we may use `_x` eventually, but our code is a work-in-progress
// and we just wanted to get rid of a compiler warning for now.
let _x = 42;
let x = 13;
let x = x + 3;
// using `x` after that line only refers to the second `x`,
// the first `x` no longer exists.
let pair = ('a', 17);
pair.0; // this is 'a'
pair.1; // this is 17
let pair: (char, i32) = ('a', 17);
let (some_char, some_int) = ('a', 17);
// now, `some_char` is 'a', and `some_int` is 17
let (left, right) = slice.split_at(middle);
let (_, right) = slice.split_at(middle);
let x = 3;
let y = 5;
let z = y + x;
let x = vec![1, 2, 3, 4, 5, 6, 7, 8]
.iter()
.map(|x| x + 3)
.fold(0, |x, y| x + y);
fn greet() {
println!("Hi there!");
}
fn fair_dice_roll() -> i32 {
4
}
// This prints "in", then "out"
fn main() {
let x = "out";
{
// this is a different `x`
let x = "in";
println!(x);
}
println!(x);
}
// this:
let x = 42;
// is equivalent to this:
let x = { 42 };
let x = {
let y = 1; // first statement
let z = 2; // second statement
y + z // this is the *tail* - what the whole block will evaluate to
};
fn fair_dice_roll() -> i32 {
return 4;
}
fn fair_dice_roll() -> i32 {
4
}
fn fair_dice_roll() -> i32 {
if feeling_lucky {
6
} else {
4
}
}
fn fair_dice_roll() -> i32 {
match feeling_lucky {
true => 6,
false => 4,
}
}
let a = (10, 20);
a.0; // this is 10
let amos = get_some_struct();
amos.nickname; // this is "fasterthanlime"
let nick = "fasterthanlime";
nick.len(); // this is 14
let least = std::cmp::min(3, 8); // this is 3
use std::cmp::min;
let least = min(7, 1); // this is 1
// this works:
use std::cmp::min;
use std::cmp::max;
// this also works:
use std::cmp::{min, max};
// this also works!
use std::{cmp::min, cmp::max};
// this brings `min` and `max` in scope, and many other things
use std::cmp::*;
let x = "amos".len(); // this is 4
let x = str::len("amos"); // this is also 4
// `Vec` is a regular struct, not a primitive type
let v = Vec::new();
// this is exactly the same code, but with the *full* path to `Vec`
let v = std::vec::Vec::new()
use std::prelude::v1::*;
struct Vec2 {
x: f64, // 64-bit floating point, aka "double precision"
y: f64,
}
let v1 = Vec2 { x: 1.0, y: 3.0 };
let v2 = Vec2 { y: 2.0, x: 4.0 };
// the order does not matter, only the names do
let v3 = Vec2 {
x: 14.0,
..v2
};
let v4 = Vec2 { ..v3 };
let (left, right) = slice.split_at(middle);
let v = Vec2 { x: 3.0, y: 6.0 };
let Vec2 { x, y } = v;
// `x` is now 3.0, `y` is now `6.0`
let Vec2 { x, .. } = v;
// this throws away `v.y`
struct Number {
odd: bool,
value: i32,
}
fn main() {
let one = Number { odd: true, value: 1 };
let two = Number { odd: false, value: 2 };
print_number(one);
print_number(two);
}
fn print_number(n: Number) {
if let Number { odd: true, value } = n {
println!("Odd number: {}", value);
} else if let Number { odd: false, value } = n {
println!("Even number: {}", value);
}
}
// this prints:
// Odd number: 1
// Even number: 2
多分支的 match 也是条件模式,就像 if let:
fn print_number(n: Number) {
match n {
Number { odd: true, value } => println!("Odd number: {}", value),
Number { odd: false, value } => println!("Even number: {}", value),
}
}
// this prints the same as before
match 必须是囊括所有情况的的:至少需要匹配一个条件分支。
fn print_number(n: Number) {
match n {
Number { value: 1, .. } => println!("One"),
Number { value: 2, .. } => println!("Two"),
Number { value, .. } => println!("{}", value),
// if that last arm didn't exist, we would get a compile-time error
}
}
如果非常难实现,_ 那么可以作用一个“包罗万象”的模式:
fn print_number(n: Number) {
match n.value {
1 => println!("One"),
2 => println!("Two"),
_ => println!("{}", n.value),
}
}
Type 别名
我们可以使用 type 关键字声明另一类型的别名,然后就可以像使用一个真正的类型一样使用这种类型。例如定义 Name 这种数据类型为字符串,后面就可以直接使用 Name 这种类型了。
你可以在方法中声明不同的数据类型:
struct Number {
odd: bool,
value: i32,
}
impl Number {
fn is_strictly_positive(self) -> bool {
self.value > 0
}
}
然后就如同往常那样使用:
fn main() {
let minus_two = Number {
odd: false,
value: -2,
};
println!("positive? {}", minus_two.is_strictly_positive());
// this prints "positive? false"
}
默认情况下,声明变量后它就就是不可变的,如下 odd 不能被重新赋值:
fn main() {
let n = Number {
odd: true,
value: 17,
};
n.odd = false; // error: cannot assign to `n.odd`,
// as `n` is not declared to be mutable
}
不可变的变量声明,其内部也是不可变的,它也不能重新分配值:
fn main() {
let n = Number {
odd: true,
value: 17,
};
n = Number {
odd: false,
value: 22,
}; // error: cannot assign twice to immutable variable `n`
}
mut 可以使变量声明变为可变的:
fn main() {
let mut n = Number {
odd: true,
value: 17,
}
n.value = 19; // all good
}
Traits 描述的是多种数据类型的共同点:
trait Signed {
fn is_strictly_negative(self) -> bool;
}
我们可以在我们定义的 Type 类型中定义 Traits:
impl Signed for Number {
fn is_strictly_negative(self) -> bool {
self.value < 0
}
}
fn main() {
let n = Number { odd: false, value: -44 };
println!("{}", n.is_strictly_negative()); // prints "true"
}
外部类型(foreign type)中定义的 Trait:
impl Signed for i32 {
fn is_strictly_negative(self) -> bool {
self < 0
}
}
fn main() {
let n: i32 = -44;
println!("{}", n.is_strictly_negative()); // prints "true"
}
impl 模块通常会带有一个 Type 类型,所以在模块内,Self 就表示该类型:
impl std::ops::Neg for Number {
type Output = Self;
fn neg(self) -> Self {
Self {
value: -self.value,
odd: self.odd,
}
}
}
有一些traits只是作为标记,它们并不是说 Type 类型实现了某些方法,它只是表明某些东西能通过Type类型完成。例如,i32 实现了Copy,那么以下代码就是可行的:
fn main() {
let a: i32 = 15;
let b = a; // `a` is copied
let c = a; // `a` is copied again
}
下面的代码也是能运行的:
fn print_i32(x: i32) {
println!("x = {}", x);
}
fn main() {
let a: i32 = 15;
print_i32(a); // `a` is copied
print_i32(a); // `a` is copied again
}
但是 Number 的结构体并不能用于 Copy,所以下面的代码会报错:
fn main() {
let n = Number { odd: true, value: 51 };
let m = n; // `n` is moved into `m`
let o = n; // error: use of moved value: `n`
}
同样下面的代码也不会 Work:
fn print_number(n: Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}
fn main() {
let n = Number { odd: true, value: 51 };
print_number(n); // `n` is moved
print_number(n); // error: use of moved value: `n`
}
但是如果print_number有一个不可变reference,那么 Copy 就是可行的:
fn print_number(n: &Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}
fn main() {
let n = Number { odd: true, value: 51 };
print_number(&n); // `n` is borrowed for the time of the call
print_number(&n); // `n` is borrowed again
}
如果函数采用了可变reference,那也是可行的,只不过需要在变量声明中带上 mut。
fn invert(n: &mut Number) {
n.value = -n.value;
}
fn print_number(n: &Number) {
println!("{} number {}", if n.odd { "odd" } else { "even" }, n.value);
}
fn main() {
// this time, `n` is mutable
let mut n = Number { odd: true, value: 51 };
print_number(&n);
invert(&mut n); // `n is borrowed mutably - everything is explicit
print_number(&n);
}
Copy 这类标记型的traits并不带有方法:
// note: `Copy` requires that `Clone` is implemented too
impl std::clone::Clone for Number {
fn clone(&self) -> Self {
Self { ..*self }
}
}
impl std::marker::Copy for Number {}
现在 Clone 仍然可以用于:
fn main() {
let n = Number { odd: true, value: 51 };
let m = n.clone();
let o = n.clone();
}
但是Number的值将不会再移除:
fn main() {
let n = Number { odd: true, value: 51 };
let m = n; // `m` is a copy of `n`
let o = n; // same. `n` is neither moved nor borrowed.
}
有一些traits很常见,它们可以通过使用derive 属性自动实现:
#[derive(Clone, Copy)]
struct Number {
odd: bool,
value: i32,
}
// this expands to `impl Clone for Number` and `impl Copy for Number` blocks.