#[derive(Debug)]
struct MoveStruct {
x: Box<i32>,
y: Box<i64>,
}
fn main() {
let moveTest = MoveStruct{ x: Box::new(23), y: Box::new(43) };
let d = moveTest.x;
let x = moveTest;
// let c = moveTest.y;
println!("hello2dj {:?}", x);
}
// 报错
src/main.rs:64:7
|
63 | let d = moveTest.x;
| - value moved here
64 | let x = moveTest;
| ^ value used here after move
|
= note: move occurs because `moveTest.x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
但若是不在使用moveTest就可以了
let d = moveTest.x;
// let x = moveTest;
let c = moveTest.y;
ok
#[derive(Debug)]
struct A {
a: i32,
b: B
}
#[derive(Debug)]
struct B {
c: i32,
d: i32
}
fn main() {
let pair = (0, -2);
let pa = A{a: 2, b: B {c: 23, d:23}};
// 试一试 ^ 将不同的值赋给 `pair`
let A { a:_, b: d } = pa; // 此处相当于move pa.b 给了d
println!("Tell me about {:?}", pair);
// match 可以解构一个元组
match pa {
// 绑定到第二个元素, 此处也是如此把 pa.d move给了 d
A{ a: _, b: d} => println!("First is `0` and `y` is `{:?}`", d),
_ => println!("It doesn't matter what they are"),
// `_` 表示不将值绑定到变量
}
println!("Tell me about {:?}", pa);
}
// 上面编译是会报错的
use partially moved value: pa
rust match 表达式返回最后一个不带分号的表达式的结果
let c : i32 = match result {
Err(err) => {
2
}
Ok(record) => {
1
}
};
// 都带上分号则c的类型是();
let c : () = match result {
Err(err) => {
2;
}
Ok(record) => {
1;
}
};
fn main() {
let a = Container {
x: 32u32,
};
let d = &a;
d.operation(); // 报错我们不可以把借用的内容move出去, 除非我们Container实现了Copy.
// cannot move out of borrowed content
fn (c: &mut A) {
let e = mem::replace(&mut c.a, Box::new(0)) // error, 不允许move 借用的content
}
4. 借用也是不允许move其中的字段的
struct A {
a: Box,
}
fn (c: &A) {
let e = c.a // error, 不允许move 借用的content
}
# *** 强调
1. 借用不允许move字段,可以使用replace::mem来进行或者clone
2. Box只允许move一个字段,且原始值不可以在使用
3. Struct 可以move多个字段,但原始值不可再使用
### 在rust中想要保持多个& mut 即多个可变引用就得是用* mut unsafe原始指针了,或者RefCell<>
### 内部可变性的类型有Mutex(这个的本质是所有权都归了他管他自然可以返回), Cell, RefCell
1. 单线程内可以使用cell和RefCell
2. 多线程就得使用Mutex
### rust 字符串拼接为什么需要借用
https://zhuanlan.zhihu.com/p/24486743
### 如何获取struct中的多字段 &
不写这些getter,直接访问field。
这种办法是可以通过的。原因在于:Rust对于内部不同的访问路径是会分开记录borrow的,所以不会有任何问题。
### move also a byte-copy but it is a semantic copy
证明move是copy的代码
https://play.rust-lang.org/?gist=2aafa34d69af1bdb04b0299d2dfb4f87&version=stable&mode=debug&edition=2015
[derive(Debug)]
struct A<'a> {
array: [i32; 4],
a: &'a i32,
}
fn main() {
let c = [2i32, 3,4,5];
let mut a = A{array: c, a: &c[0]};
let mut d = a;
d.array[0] = 1234;
// *(d.a) = 12455;
println!("{:?}, {:?}", d.a, d);
}
// 结果
// 2, A { array: [1234, 3, 4, 5], a: 2 }
### [trait objects lifetime](https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html?highlight=traits,object#inference-of-trait-object-lifetimes)
1. The default lifetime of a trait object is 'static
2. With &'a Trait or &'a mut Trait, the default lifetime of the trait object is 'a.
3. With a single T: 'a clause, the default lifetime of the trait object is 'a.
4. With multiple clauses like T: 'a, there is no default lifetime; we must be explicit.
* trait objects are "&Foo or Box<Foo>"
cause trait objects的default lifetime is 'static
### object safe
recap
Whew! As we can see, almost all of these rules talk about Self. A good intuition is “except in special circumstances, if your trait’s method uses Self, it is not object-safe.”
### [why Box<Trait> need lifetime](https://morestina.net/blog/793/closure-lifetimes-in-rust)
trait object's default lifetime is 'static, the captures must be 'static, otherwise there will be invalidate reference.
fn crash_rust() {
let mut p = Processor::new();
{
let s = "hi".to_string();
p.set_callback(|| println!("{}", s.len()));
}
// access to destroyed "s"!
p.invoke();
}
when we call invoke, the s has alreay been release.
### 不带分号的句子只是返回到上一层并不是函数调用返回
match a {
1 => { 32; }
=> { false }
// => { return flase; }
}
此时就会报错因为1对应的分支match返回 (),而_对应的分支返回false; 是编译不过的。
### rust macro 输入的是token串, 输出的是AST, https://danielkeep.github.io/tlborm/book
As previously mentioned, macro processing in Rust happens after the construction of the AST. As such, the syntax used to invoke a macro must be a proper part of the language's syntax.
1. ident: 标识符,用来表示函数或变量名 如 a, b, foo等等 'an identifier. Examples: x; foo.'
2. expr: 表达式 a + b, a * b, foo(23)等, '2 + 2; if true then { 1 } else { 2 }; f(42)' 'an expression. Examples: 2 + 2; if true then { 1 } else { 2 }; f(42).'
3. block: 代码块,用花括号包起来的多个语句 {}, () 'a brace-delimited sequence of statements. Example: { log(error, "hi"); return 12; }.'
4. pat: 模式,普通模式匹配(非宏本身的模式)中的模式,例如 Some(t), (3, 'a', _), let, match, 'Some(t); (17, 'a'); _.' 'a pattern. Examples: Some(t); (17, 'a'); _.'
5. path: 路径,注意这里不是操作系统中的文件路径,而是用双冒号分隔的限定名(qualified name),如 std::cmp::PartialOrd 'a qualified name. Example: T::SpecialA.'
6. tt(token tree): 单个语法树 (可以是任意的rust语法)'a single token tree.'
7. ty(type): 类型,语义层面的类型,如 i32, char 'a type. Examples: i32; Vec<(char, String)>; &T.'
9. item: 条目,function, struct, module, 'fn foo() { }; struct Bar;' 'an item. Examples: fn foo() { }; struct Bar;.'
10. meta: 元条目 如#[...] and #![...], 'cfg(target_os = "windows")' 'a "meta item", as found in attributes. Example: cfg(target_os = "windows").'
11. stmt: 单条语句,如 let a = 42; 'a single statement. Example: let x = 3.'
> expr: variables must be followed by one of: => , ;
> ty and path variables must be followed by one of: => , : = > as
> pat variables must be followed by one of: => , =
> Other variables may be followed by any token.
> item: anything.
block: anything.
stmt: => , ;
pat: => , = if in
expr: => , ;
ty: , => : = > ; as
ident: anything.
path: , => : = > ; as
meta: anything.
tt: anything.
### rust的宏匹配以后再有其他宏进行匹配时传入的是AST node无法再进行细致的token匹配,因此在模块化的宏是困难的。
recognise_tree!(expand_to_larch!());
这里expand_to_larch也是个宏 可是对于宏来书输入就是token tree, 因此是不会展开expand_to_larch的;
https://danielkeep.github.io/tlborm/book/mbe-min-captures-and-expansion-redux.html
By parsing the input into an AST node, the substituted result becomes un-destructible
当我们把token tree 解析成AST node以后就无法再结构进行匹配了,因为AST node是个完整的语法,破坏了就没有语义了, 而token 还没有进行语义分析呢
词法解析器 -> token tree
语法解析器 -> AST node
### macro 匹配时是token tree匹配的因此无论写什么都可以因为他只一个token stream,还没有解析,但进入到macro扩展的阶段就是AST node了,这时匹配到的肯定都是合法的rust syntax了。
1. The input to every macro is a single non-leaf token tree.
2. Macros (really, syntax extensions in general) are parsed as part of the abstract syntax tree.
3. There are multiple kinds of syntax extension in Rust. We will only be talking about macros defined by the macro_rules! construct.
4. Just because you see something of the form $name! $arg, doesn't mean it's actually a macro; it might be another kind of syntax extension.
### 被宏匹配过的token tree中的匹配项就是一个整体(匹配中的匹配项),不能再拆卡匹配了,也就是说嵌套宏是无法进行再次拆开匹配的功能,只有token tree 才能拆开匹配
就好比 下面的 '3 + 5', 再直接用match_tokens 匹配,那还能拆开为a + b, 但经过 capture_then_match_tokens 匹配后就是个整体的expr,再去用match_tokens进行匹配也是不行的。
e, init_array!(@accum 2, e) // 这就是个残缺的 因此不合法, e, 加个啥?
7. Token trees are somewhere between tokens and the AST. Firstly, almost all tokens are also token trees; more specifically, they are leaves. There is one other kind of thing that can be a token tree leaf, but we will come back to that later.
The only basic tokens that are not leaves are the "grouping" tokens: (...), [...], and {...}. These three are the interior nodes of token trees, and what give them their structure. To give a concrete example, this sequence of tokens:
a + b + (c + d[0]) + e
按照上面所说的 所有的tokens都是token trees 大部分也都是叶子,只有 (). {}. []不是,因此 上面的那个表达式一共有 7 个 single token tree;
a, +, b, +, (c + d[0]), +, e
> 怎么推断的呢? $(($t:tt)*) 有多少个$t就有多少个 single token tree
### [rust 中的vector之一种值] // 待理解
rust 默认语义是move(也是通过按字节copy实现的)
rust中的变量是 某块内存的名字, mut 标志的是名字对应的内存区域是否可变
rust enum 是不可以使用 == 进行比较的, 其他比较也是不可以的
rust的所有权问题当一个结构体中的一个字段move出去以后那么整个结构体就不能再使用了,但是,内部字段还可以继续使用
但若是不在使用moveTest就可以了
rust 的结构体,只要结构体是可变的,那么内部字段就都是可变的,不存在部分可变,部分不可变的情况(RefCell不算)
rust 在调用*解引用时是这么的步骤
{integer}
cannot be dereferencedrust 的变量一旦被可变借用后,其原始值就不能再用了, 再有其他借用也不可以,无论是可变还是不可变。
总结一下
结构时也是遵循copy和move,以及借用规则的
rust match 表达式返回最后一个不带分号的表达式的结果
这是一种方法调用, From::from(type), 调用type的from方法
rust的方法调用与golang一样,无论方法定义时的接收者是引用还是值,这两个方法都会替我们进行解引用或者引用直到找到符合的方法。
rust中有一个trait object, Box, 并且给他实现了
这意味着我们都可以把Error类型转换到Box
rust的mod也可以以文件的形式组织,当前提是在使用时得先写mod module, 来引入
only auto traits can be used as additional traits in a trait object
auto traits 是指编译器会自动实现的trait, 例如Send , Sync
当编译器做使用了如下三个规则来推测生命周期之后还有未推测出来的生命周期时就会报错,也就意味着,这些还未推测出来的生命周期需要我们手动声明
fn foo<'a>(x: &'a i32, x: &'b i32) -> &'a i32
fn foo(&'a self) -> &'a str
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str where T: Display { println!("Announcement! {}", ann); if x.len() > y.len() { x } else { y } }
struct A { // T可以是&类型,就相当于&'a SomeType,不需要在另外声明
a: T,
}
use std::sync::Arc; struct A {
it: Arc, // 这里的T可以是引用那么他的生命周期是如何确定的
ie: B,
}
struct B {
it: Arc,
}
&d.it
error: aborting due to previous error
error: Could not compile
playground
. }trait Operation { fn operation(self); } impl Operation for u32 { fn operation(&self){ // 这里就会报错因为接受者参数写成了&self, 而不是self,这里的self就是u32 self; } }
// 调用的时候就可以使用 let a = 32u32; a.operation();
// 甚至使用&来调用 let a = 32u32; let d = &a; d.operation();
trait Operation { fn operation(self); }
struct Container {
x:T
}
impl Operation for Container {
fn operation(self){
println!("dengjie");
self;
}
}
fn main() { let a = Container { x: 32u32, }; let d = &a; d.operation(); // 报错我们不可以把借用的内容move出去, 除非我们Container实现了Copy. // cannot move out of borrowed content
}
struct A { a: i32
}
impl A { fn say(&self) { println!("{:?}", self.a); } }
fn main() { let c = &&&A {a : 234}; c.say(); }
struct A { a: Box,
b: Box,
}
fn test() { let a = A{a..., b...}; let d = a.a; // ok let e = &a; // error let c = a.b; // ok
}
struct A { a: Box,
}
fn (c: &mut A) { let e = mem::replace(&mut c.a, Box::new(0)) // error, 不允许move 借用的content }
struct A { a: Box,
}
fn (c: &A) { let e = c.a // error, 不允许move 借用的content }
[derive(Debug)]
struct A<'a> { array: [i32; 4], a: &'a i32, }
fn main() {
} // 结果 // 2, A { array: [1234, 3, 4, 5], a: 2 }
fn crash_rust() { let mut p = Processor::new(); { let s = "hi".to_string(); p.set_callback(|| println!("{}", s.len())); } // access to destroyed "s"! p.invoke(); }
match a { 1 => { 32; } => { false } // => { return flase; } }
recognise_tree!(expand_to_larch!());
macro_rules! capture_then_what_is { (#[$m:meta]) => {what_is!(#[$m])}; }
macro_rules! what_is { (#[no_mangle]) => {"no_mangle attribute"}; (#[inline]) => {"inline attribute"}; ($($tts:tt)) => {concat!("something else (", stringify!($($tts)), ")")}; }
fn main() { println!( "{}\n{}\n{}\n{}", what_is!(#[no_mangle]), what_is!(#[inline]), capture_then_what_is!(#[no_mangle]), capture_then_what_is!(#[inline]), ); }
macro_rules! capture_then_match_tokens { ($e:expr) => {match_tokens!($e)}; }
macro_rules! match_tokens { ($a:tt + $b:tt) => { {println!("{:}, {:}", stringify!($a), stringify!($b)); "got an addition"} }; (($i:ident)) => { { println!("{:}", stringify!($i)); "got an identifier" }}; ($($other:tt)) => { { println!("{:}", stringify!($($other))); "got something else"} }; }
fn main() { println!("{}\n{}\n{}\n", match_tokens!((caravan)), match_tokens!(3 + 6), match_tokens!(5)); println!("{}\n{}\n{}", capture_then_match_tokens!((caravan)), capture_then_match_tokens!(3 + 6), capture_then_match_tokens!(5)); }
[derive(Clone)]
pub enum Entry<K,V> { Empty, Full(K, V, u64), Ghost(K, u64), }
impl<K,V> Entry<K,V> {
[inline]
}
macro_rules! dead_rule { ($e:expr) => { ... }; ($i:ident +) => { ... }; }
macro_rules! capture_expr_then_stringify { ($e:expr) => { stringify!($e) }; }
fn main() { println!("{:?}", stringify!(dummy(2 (1 + (3))))); println!("{:?}", capture_expr_then_stringify!(dummy(2 (1 + (3))))); }
┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐ │ Var │╶┘ └─────────┘ └╴│ BinOp │ │ name: a │ │ op: Add │ └─────────┘ ┌╴│ lhs: ◌ │ ┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐ │ Var │╶┘ └─────────┘ └╴│ BinOp │ │ name: b │ │ op: Add │ └─────────┘ ┌╴│ lhs: ◌ │ ┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐ │ BinOp │╶┘ └─────────┘ └╴│ Var │ │ op: Add │ │ name: e │ ┌╴│ lhs: ◌ │ └─────────┘ ┌─────────┐ │ │ rhs: ◌ │╶┐ ┌─────────┐ │ Var │╶┘ └─────────┘ └╴│ Index │ │ name: c │ ┌╴│ arr: ◌ │ └─────────┘ ┌─────────┐ │ │ ind: ◌ │╶┐ ┌─────────┐ │ Var │╶┘ └─────────┘ └╴│ LitInt │ │ name: d │ │ val: 0 │ └─────────┘ └─────────┘
macro_rules! foo { () => {{ ... }} }
e, init_array!(@accum 2, e) // 这就是个残缺的 因此不合法, e, 加个啥?
a + b + (c + d[0]) + e