Generics(泛型)
Generics是Rust中的重要内容,能够最大化地减少代码的重复。fn foo<T>(arg: T) { ... }
来定义一个函数,传入的参数为T
。
1
2
3
4
5
6
7
8
9
10
11
12
|
struct Val {
val: f64,
}
impl Val {
pub fn value(&self) -> &f64 {
&self.val
}
}
fn main() {
let x = Val { val: 3. };
let y = x.value();
}
|
trait(接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//定义接口
trait HasArea {
fn area(&self) -> f64;
}
struct Rectangle { length: f64, height: f64 }
// 实现接口
impl HasArea for Rectangle {
fn area(&self) -> f64 {
self.length * self.height
}
}
//方法
fn area<T: HasArea>(t: &T) -> f64 { t.area() }
fn main() {
let r = Rectangle { length: 5., height: 4. };
let x = r.area();
println!("{}", x);
}
|
如果没有实现接口,就会出现错误。在java中可以实现多个接口,那么rust中也是可以的。
1
2
3
4
5
6
7
8
9
10
|
use std::fmt::{Debug, Display, Formatter, Error, Result};
fn compare_prints<T: Debug + Display>(t: &T) {
println!("Debug: `{:?}`", t);
println!("Display: `{}`", t);
}
fn main() {
let string = "words";
let array = [1, 2, 3];
compare_prints(&string);
}
|
where(限定符)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
use std::fmt::Debug;
trait PrintInOption {
fn print_in_option(self);
}
// Because we would otherwise have to express this as `T: Debug` or
// use another method of indirect approach, this requires a `where` clause:
impl<T> PrintInOption for T where
Option<T>: Debug {
// We want `Option<T>: Debug` as our bound because that is what's
// being printed. Doing otherwise would be using the wrong bound.
fn print_in_option(self) {
println!("{:?}", Some(self));
}
}
fn main() {
let vec = vec![1, 2, 3];
vec.print_in_option();
}
|
作用域规则
在Rust语言中,作用域规则非常重要,这也是Rust语言的垃圾回收的重要机制。Rust对变量的处理不仅仅是只分配空间,同时掌握着变量的生存周期,一旦一个变量离开了上下文,那么就使用垃圾回收将其回收。RAIIRAII-wiki内存泄露工具可以使用valgrind
在Rust中,资源只能有一个所有者,不仅仅能够保证资源不会泄露,同时保证了资源不会被释放两次。当资源的所有者被转移以后,之前的所有者就不存在了,这样也就避免了悬挂指针的出现。
在Rust中,有堆和栈的区别。堆分配非常慢,而栈非常快,使用Box::new()
则是在堆中分配。
1
2
3
|
let x = Box::new(4i32);
let y = x;
print!("{}", x);
|
在这里,x就没有用,因为所有权已经被转移到y上。
借用(Borrowing)
很多时候我们不想取得变量的所有权,我们只想得到变量的值,那么这个时候就采用借用,使用&T
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
fn eat_box_i32(boxed_i32: Box<i32>) {
println!("Destroying box that contains {}", boxed_i32);
}
fn borrow_i32(borrowed_i32: &i32) {
println!("This int is: {}", borrowed_i32);
}
fn main() {
let boxed_i32 = Box::new(5_i32);
let stacked_i32 = 6_i32;
borrow_i32(&boxed_i32);
println!("{}", boxed_i32);
}
//下面两个是一样的
let ref ref_c1 = c;
let ref_c2 = &c;
|
生命周期(lifetime)
1
2
3
4
5
6
7
8
|
struct Object {
number: u32
}
struct Multiplier {
object: &Object,
mult: u32
}
|
- 首先定义了一个结构体
Object
,然后里面有一个内容number
,这没有问题。
- 其次定义了
Multiplier
,然后里面有mult
,以及object
。
这里就出现问题了,object
可能生存任何期间,也就是比Multiplier
生命周期短!这就是问题,
Rust是这样定义生命周期
1
2
3
4
|
struct Multiplier<'a> {
object: &'a Object,
mult: u32
}
|
有一个结构体生命周期为’a,同时有一个object的生命周期至少与’a一样长
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
struct Object {
number: i32,
}
fn object_combinator<'a, 'b>(a: &'a mut Object, b: &'b Object) -> &'a mut Object {
a.number = a.number + b.number;
a
}
fn main() {
let mut a = Object { number: 3 };
let b = Object { number: 4 };
println!("Result: {}", object_combinator(&mut a, &b).number);
}
//意味着该变量存在与整个程序
let string: &'static str = "I'm a string! Yay!";
|
参考