Open yetone opened 7 years ago
所有权系统是为了管理堆上的值。
记录何处的代码在使用堆上的什么数据,最小化堆上的冗余数据的数量以及清理堆上不再使用的数据以致不至于耗尽空间,这些所有的问题正是所有权系统要处理的。
所有者就是变量。值有且只有一个所有者(变量)。
当所有者离开作用域(scope)后,值就会被丢弃(释放内存)。
类型构造器就是一些带有泛型/模板参数的类型。当填满了参数,才会成为一个实际的类型。& 和 &mut 都是类型构造器,它们的参数是生命周期和具体的类型。
let s1 = String::from("hello");
let s2 = s1; // move
获得所有权
let s = &s1;
不获得所有权
let mut a = 1;
let b = &mut a;
- borrow of `a` occurs here
let c = a + 1;
^ use of borrowed `a`
error[E0503]: cannot use `a` because it was mutably borrowed
下面是正常的,嘻嘻:
let mut a = 1;
let b = &a;
let c = a + 1;
let mut a = 1;
let b = &a;
- borrow of `a` occurs here
a = 2;
^^^^^ assignment to borrowed `a` occurs here
error[E0506]: cannot assign to `a` because it is borrowed
#![allow(unused_variables)]
#[derive(Debug)]
struct A(i32);
#[derive(Debug)]
struct B {
a: A,
aa: A,
}
fn main() {
let b = B { a: A(1), aa: A(2) };
let a = b.a;
// - value moved here
println!("{:?}", b);
// ^ value used here after move
}
To fix it:
#![allow(unused_variables)]
#[derive(Debug, Copy, Clone)] // <- important
struct A(i32);
#[derive(Debug)]
struct B {
a: A,
aa: A,
}
fn main() {
let b = B { a: A(1), aa: A(2) };
let a = b.a;
println!("{:?}", b);
}
Alternative
let b = &B { a: A(1), aa: A(2) };
let a = &b.a;
println!("{:?}", b);
If you:
let b = &B { a: A(1), aa: A(2) };
let a = b.a;
//| ^---
//| |
//| cannot move out of borrowed content
//| help: consider using a reference instead: `&b.a`
println!("{:?}", b);
除了 let, match, if let, while let 以外,函数参数也支持模式匹配哦!!!(我好蠢,我现在才知道 -,-
use std::ops::BitOr;
#[derive(Debug, PartialEq)]
struct BooleanVector(Vec<bool>);
impl BitOr for BooleanVector {
type Output = Self;
fn bitor(self, BooleanVector(rhs): Self) -> Self {
// ^ rhs: Vec<_>
let BooleanVector(lhs) = self;
assert_eq!(lhs.len(), rhs.len());
BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect())
}
}
let bv1 = BooleanVector(vec![true, true, false, false]);
let bv2 = BooleanVector(vec![true, false, true, false]);
let expected = BooleanVector(vec![true, true, true, false]);
assert_eq!(bv1 | bv2, expected);
let a = &1;
match a {
&x if x > 1 => println("a: {}", x),
_ => println("hehe")
}
let a = &mut 1;
match a {
&mut x if x > 1 => println("a: {}", x),
_ => println("hehe")
}
看起来像继承,其实不是继承啊,傻子
trait A {}
trait B: A {}
意味着,你要实现 B,必须得先实现 A:
struct S;
impl A for S; // 如果漏掉了这一行就跪了
impl B for S;
!
是 never type,可以强制转换成任意类型,嘻嘻
其实就是 bottom type 而已(官方承认了
struct Foo<T>(T);
struct Bar<T: ?Sized>(T);
// struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
struct BarUse(Bar<[i32]>); // OK
trait T {
fn test(self) {}
^^^^ doesn't have a size known at compile-time
}
error[E0277]: the size for values of type `Self` cannot be known at compilation time
下面是好的:
trait T: Sized {
fn test(self) {}
}
或者:
trait T {
fn test(self) where Self: Sized {}
}
因为局部变量、函数参数、函数返回值都是放在栈上的,所以要求它们必须大小已知且固定,所以它们必须是 Sized,所以泛型参数默认是 Sized:
fn test<T>(a: T) {}
上面是合法的,因为默认 T: Sized
,但是为什么给我们一个 ?Sized
用来去掉 Sized bound 的功能呢?想象下面的情况:
fn test<T>(a: &T) {}
是不是 T 即使可变大小也是合法的?(因为指针是固定大小的),所以上面的函数可以:
fn test<T: ?Sized>(a: &T) {}
生命周期就是一个区间,生命周期参数就是一个普通的泛型参数,它可以被特化为某个具体的生命周期。
let a = 1;
let b = a + 1;
let a = &1;
let b = a + 1; // 正常
let a = &mut 1;
let b = a + 1; // 报错
// error[E0369]: binary operation `+` cannot be applied to type `&mut {integer}`
因为 std::ops::Add
只为 i32 实现了两个:
fn add(self, i32) -> i32;
fn add(&self, &i32) -> i32;
你说气人不气人?!
两种方法,第一种是利用 rust 的类型系统的报错信息:
fn t(_x: ()) {}
let ref a = 1;
t(a);
第二种比较高级:
#![feature(core_intrinsics)]
fn pt<T>(_arg: &T) {
unsafe {
println!("{}", std::intrinsics::type_name::<T>());
}
}
let ref a = 1;
pt(&a);
macro_rules! timeit {
($e:expr) => {{
use std::time;
let st = time::SystemTime::now();
let rest = $e;
match st.elapsed() {
Ok(elapsed) => {
println!(
"{} cost: {}",
stringify!($e),
if elapsed.as_secs() > 1 {
format!("{}s", elapsed.as_secs())
} else if elapsed.as_millis() > 1 {
format!("{}ms", elapsed.as_millis())
} else if elapsed.as_micros() > 1 {
format!("{}μs", elapsed.as_micros())
} else {
format!("{}ns", elapsed.as_nanos())
}
);
}
Err(_) => {}
}
rest
}};
}
let a = timeit!(1 + 1);
dynamic trait
其实就是 &Trait
, &mut Trait
, Box<Trait>
,这么做是为了和 impl Trait
相对应:
&dyn Trait
, &mut dyn Trait
, Box<dyn Trait>
详见:https://joshleeb.com/posts/rust-traits-and-trait-objects/·
其实 |x| x + 1
并不是一个 closure,因为并没有捕获局部变量(非常量和静态变量),所以 rust 只会把它当作普通函数处理:
let plus_one: fn(i32) -> i32 = |x| x + 1; // 这是合法的
const a: i32 = 1;
let plus_one: fn(i32) -> i32 = |x| x + a; // 这也是合法的
static a: i32 = 1;
let plus_one: fn(i32) -> i32 = |x| x + a; // 这同样是合法的
作为对比,下面的情况会报错:
let a = 1;
let plus_one: fn(i32) -> i32 = |x| x + a; // 这是不合法的,因为 |x| x + a 是个 closure 并不是 function pointer
$name! $arg
这种形式的调用并不代表其是一个宏,它可能是另一种语法扩展最后一点是十分重要的,因为它有重要的意义。因为宏被解析成另 AST,它只能出现在明确支持的位置。 具体来说,宏只能出现在下列位置:
解引用强制多态会自动的将指针或智能指针的引用转换为指针内容的引用。
解引用时 rust 会偷偷地调用 deref 方法:
强制解引用多态是针对函数参数的,是 rust 为了方便传递引用类型的参数而提供的语法糖,为了把不匹配的引用类型转换成与函数签名中的参数相同的类型而做的语法糖:
scan 和 fold 的区别:
scan 是个适配器(返回 Iterator),fold 是个消费器(返回实现了 FromIter 的类型)。scan closure 的第一个参数是个可变引用 &mut,每次迭代需要改变第一个参数,且 closure 的返回值需要是个 Optional
输出:
slice a &str