Rust学习笔记
1.Tuples,Arrays和slice的区别
Tuples是不同类型元素的集合,Arrays和slice是相同元素的集合。但是不同之处在于,arrays在编译时就知道其长度,而slice在编译时不知道其长度。slice经常用来取arrays的某一部分作为切片,如下面的例程所示:
use std::mem;
// This function borrows a slice
fn analyze_slice(slice: &[i32]) {
println!("first element of the slice: {}", slice[0]);
println!("the slice has {} elements", slice.len());
}
fn main() {
// Fixed-size array (type signature is superfluous)
let xs: [i32; 5] = [1, 2, 3, 4, 5];
// All elements can be initialized to the same value
let ys: [i32; 500] = [0; 500];
// Indexing starts at 0
println!("first element of the array: {}", xs[0]);
println!("second element of the array: {}", xs[1]);
// `len` returns the count of elements in the array
println!("number of elements in array: {}", xs.len());
// Arrays are stack allocated
println!("array occupies {} bytes", mem::size_of_val(&xs));
// Arrays can be automatically borrowed as slices
println!("borrow the whole array as a slice");
analyze_slice(&xs);
// Slices can point to a section of an array
// They are of the form [starting_index..ending_index]
// starting_index is the first position in the slice
// ending_index is one more than the last position in the slice
println!("borrow a section of the array as a slice");
analyze_slice(&ys[1 .. 4]);
// Out of bound indexing causes compile error
println!("{}", xs[5]);
}
运行结果:
first element of the array: 1
second element of the array: 2
number of elements in array: 5
array occupies 20 bytes
borrow the whole array as a slice
first element of the slice: 1
the slice has 5 elements
borrow a section of the array as a slice
first element of the slice: 0
the slice has 3 elements
总结:注意slice的analyze_slice(&ys[1 … 4]);这种截取用法。
2.自定义类型
Rust的自定义类型分为struct和enum两种。
struct的三种定义形式:
// A unit struct
struct Unit;
// A tuple struct
struct Pair(i32, f32);
// A struct with two fields
struct Point {
x: f32,
y: f32,
}
enum经常被使用来构成链表这种数据结构。
3.变量绑定
用let进行绑定,如果绑定的变量,未被使用,会报warning。如果按如下方式定义,即在变量前加下划线_,可以防止warning。
// The compiler warns about unused variable bindings; these warnings can
// be silenced by prefixing the variable name with an underscore
let _unused_variable = 3u32;
let _noisy_unused_variable = 2u32;
// FIXME ^ Prefix with an underscore to suppress the warning
默认情况下变量绑定是不能再改变的,但是如果用mut修饰的变量绑定后,也是可以改变的。
fn main() {
let _immutable_binding = 1;
let mut mutable_binding = 1;
println!("Before mutation: {}", mutable_binding);
// Ok
mutable_binding += 1;
println!("After mutation: {}", mutable_binding);
// Error!
_immutable_binding += 1;
// FIXME ^ Comment out this line
}
变量绑定是有生效范围的,一般在{}大括号包起来的块里生效:
fn main() {
// This binding lives in the main function
let long_lived_binding = 1;
// This is a block, and has a smaller scope than the main function
{
// This binding only exists in this block
let short_lived_binding = 2;
println!("inner short: {}", short_lived_binding);
}
// End of the block
// Error! `short_lived_binding` doesn't exist in this scope
println!("outer short: {}", short_lived_binding);
// FIXME ^ Comment out this line
println!("outer long: {}", long_lived_binding);
}
4.类型转换
可以用as关键字进行显示类型转换:
let decimal = 65.4321_f32;
// Error! No implicit conversion
let integer: u8 = decimal;
// FIXME ^ Comment out this line
// Explicit conversion
let integer = decimal as u8;
let character = integer as char;
float不能直接转换为char,要先转换为int,再由int转换为float。
// Error! There are limitations in conversion rules.
// A float cannot be directly converted to a char.
let character = decimal as char;
// FIXME ^ Comment out this line
println!("Casting: {} -> {} -> {}", decimal, integer, character);
5.迭代器
iter迭代器,iter迭代器不会消耗集合中的元素:
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.iter() {
match name {
&"Ferris" => println!("There is a rustacean among us!"),
// TODO ^ Try deleting the & and matching just "Ferris"
_ => println!("Hello {}", name),
}
}
println!("names: {:?}", names);
}
结果:
Hello Bob
Hello Frank
There is a rustacean among us!
names: [“Bob”, “Frank”, “Ferris”]
into_iter迭代器
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];
for name in names.into_iter() {
match name {
"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
}
//error,because into_iter() will consume the collection
//println!("names: {:?}", names);
// FIXME ^ Comment out this line
}
6.函数
rust函数末尾的返回值,不一定要有return。rust函数之间的顺序没有特定限制。->后接函数的返回值。
// Unlike C/C++, there's no restriction on the order of function definitions
fn main() {
// We can use this function here, and define it somewhere later
fizzbuzz_to(100);
}
// Function that returns a boolean value
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
// Corner case, early return
if rhs == 0 {
return false;
}
// This is an expression, the `return` keyword is not necessary here
lhs % rhs == 0
}
// Functions that "don't" return a value, actually return the unit type `()`
fn fizzbuzz(n: u32) -> () {
if is_divisible_by(n, 15) {
println!("fizzbuzz");
} else if is_divisible_by(n, 3) {
println!("fizz");
} else if is_divisible_by(n, 5) {
println!("buzz");
} else {
println!("{}", n);
}
}
// When a function returns `()`, the return type can be omitted from the
// signature
fn fizzbuzz_to(n: u32) {
for n in 1..n + 1 {
fizzbuzz(n);
}
}
闭包,类似函数的一种形式。
fn main() {
// Increment via closures and functions.
fn function(i: i32) -> i32 { i + 1 }
// Closures are anonymous, here we are binding them to references
// Annotation is identical to function annotation but is optional
// as are the `{}` wrapping the body. These nameless functions
// are assigned to appropriately named variables.
let closure_annotated = |i: i32| -> i32 { i + 1 };
let closure_inferred = |i | i + 1 ;
let i = 1;
// Call the function and closures.
println!("function: {}", function(i));
println!("closure_annotated: {}", closure_annotated(i));
println!("closure_inferred: {}", closure_inferred(i));
// A closure taking no arguments which returns an `i32`.
// The return type is inferred.
let one = || 1;
println!("closure returning one: {}", one());
}
7.Modules
Modules用Mod关键词定义,默认情况下,Modules中的成员是私有的,可以用pub关键词修饰成员,使其变为公有成员。
8.Crate
crate 是 Rust 中的一个编译单元。 每当 rustc some_file.rs 被调用时, some_file.rs 被视为 crate 文件。 如果 some_file.rs 中有 mod 声明,那么在运行编译器之前,模块文件的内容将插入到 crate 文件中找到 mod 声明的位置(类似内联函数)。 换句话说,模块不会被单独编译,只有 crate 会被编译。
9.cargo
cargo可以用来管理项目的依赖项。
cargo创建一个项目:
# A binary
cargo new foo
# OR A library
cargo new --lib foo
执行成功后,会出现如下的文件结构:
foo
├── Cargo.toml
└── src
└── main.rs
main.rs 是新项目的根文件。 Cargo.toml 是这个项目(foo)的cargo配置文件。 如果你看里面,你应该看到这样的东西:
[package]
name = "foo"
version = "0.1.0"
authors = ["mark"]
[dependencies]
dependencies下面可以给我们的项目添加依赖:
[package]
name = "foo"
version = "0.1.0"
authors = ["mark"]
[dependencies]
clap = "2.27.1" # from crates.io
rand = { git = "https://github.com/rust-lang-nursery/rand" } # from online repo
bar = { path = "../bar" } # from a path in the local filesystem