You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#[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;
}
};
use std::sync::Arc;
struct A<T> {
it: Arc<T>, // 这里的T可以是引用那么他的生命周期是如何确定的
ie: B<T>,
}
struct B<T> {
it: Arc<T>,
}
fn main() {
let c = 32;
let d = &A{
it: Arc::new(23),
ie: B { it: Arc::new(23) },
};
let e = d.it;
// 会报错的
| let e = d.it;
| ^---
| |
| cannot move out of borrowed content
| help: consider using a reference instead: `&d.it`
error: aborting due to previous error
error: Could not compile `playground`.
}
见上面的代码,若d不是引用则可以move,但是move过后的d是不允许在使用,只能再move出去其他字段,若是再使用的话回报use of partially moved value: d,这个错。
struct A {
a: Box<i32>,
b: Box<String>,
}
fn test() {
let a = A{a..., b...};
let d = a.a; // ok
let e = &a; // error
let c = a.b; // ok
let a = Box::new(A{a.., b...});
let d = a.a; // ok; a partial moved
let e = a.b; // used moved value a;
}
With &'a Trait or &'a mut Trait, the default lifetime of the trait object is 'a.
With a single T: 'a clause, the default lifetime of the trait object is 'a.
With multiple clauses like T: 'a, there is no default lifetime; we must be explicit.
trait objects are "&Foo or Box"
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.”
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.
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.
meta: 元条目 如#[...] and #![...], 'cfg(target_os = "windows")' 'a "meta item", as found in attributes. Example: cfg(target_os = "windows").'
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.
e, init_array!(@accum 2, e) // 这就是个残缺的 因此不合法, e, 加个啥?
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之一种值] // 待理解
The text was updated successfully, but these errors were encountered:
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
当编译器做使用了如下三个规则来推测生命周期之后还有未推测出来的生命周期时就会报错,也就意味着,这些还未推测出来的生命周期需要我们手动声明
生命周期其实也是种泛型,所以当函数使用生命周期时一定得像使用泛型一样把生命周期写在方法名后面
生命周期默认是'static的有
lifetime 就是scope,相当于scope的泛型,而我们的泛型相当于自带lifetime
对与结构体的引用,是不予许把引用的字段move出去,简而言之就是引用的内容是不允许move的
cannot move out of borrowed content
见上面的代码,若d不是引用则可以move,但是move过后的d是不允许在使用,只能再move出去其他字段,若是再使用的话回报use of partially moved value:
d
,这个错。解决引用无法move字段的方法
关于generic reference 的问题stackoverflow
通过他我们知道了,当我们的trait写是self时,那我们的self的类型就是实现的self,比如我们的trait A接收的是self参数,然后我们给i32实现了trait A, 那么接收者就必须得是i32, 再好比我们给&'a i32实现了trait A,那么接收者就的是& i32。总结就是:trait 给谁实现了比如B, 那么方法的self的类型就是B。
通过上面的栗子,我们可以看到,rust在我们进行方法的调用的时候回自动给我们解引用,但当我们的类型是不可copy的时候,自动解引用就会触发move,那么就会报错了,见下
当我们使用&和&mut时我们完全可以把他们变为* const和* mut 来使用unsafe代码来修改数据,但是unsafe代码一定得留神
Box类型和其他结构体类型不同,其他结构体其中字段被move出去以后,那么整个结构体不可再move但是其中的其他字段还是可以继续使用,Box则不同,一个字段被move以后其他字段也不能使用了。
原因是 Box是分配在堆上的空间,若是分别move,会造成堆空间的重复释放,而struct的栈上空间就不存在这个问题
for syntax
https://stackoverflow.com/questions/35592750/how-does-for-syntax-differ-from-a-regular-lifetime-bound
lifetime的省略机制
trait, impl trait, &trait, Box
https://joshleeb.com/posts/rust-traits-and-trait-objects/
rust 关于方法调用的dref和ref
https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules/28552082
定义方法实现时 方噶的receiver只能是self, &self, &mut self, 若是其他的没有self receiver 则没有限制, 含有self的只能是上面三种形式
调用时rust会自动添加ref或者dref来进行适配
如上我们给A 定义了一个&self,但我们的调用确是&&&A, rust 会自行derf到&A
当然 A和会继承Deref的方法,因为rust在调用方法时会自动去适配Deref A的
对一个不能copy的Struct既有self又有&self调用是会报错的
总结一下
str Vs String
https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str/24159933#24159933
使用rust要牢记
这意味着我们若是想使用某个借用的内容值可以使用mem::replace
*** 强调
在rust中想要保持多个& mut 即多个可变引用就得是用* mut unsafe原始指针了,或者RefCell<>
内部可变性的类型有Mutex(这个的本质是所有权都归了他管他自然可以返回), Cell, RefCell
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
trait objects lifetime
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 need lifetime
trait object's default lifetime is 'static, the captures must be 'static, otherwise there will be invalidate reference.
when we call invoke, the s has alreay been release.
不带分号的句子只是返回到上一层并不是函数调用返回
此时就会报错因为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.
ident: 标识符,用来表示函数或变量名 如 a, b, foo等等 'an identifier. Examples: x; foo.'
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).'
block: 代码块,用花括号包起来的多个语句 {}, () 'a brace-delimited sequence of statements. Example: { log(error, "hi"); return 12; }.'
pat: 模式,普通模式匹配(非宏本身的模式)中的模式,例如 Some(t), (3, 'a', _), let, match, 'Some(t); (17, 'a'); _.' 'a pattern. Examples: Some(t); (17, 'a'); _.'
path: 路径,注意这里不是操作系统中的文件路径,而是用双冒号分隔的限定名(qualified name),如 std::cmp::PartialOrd 'a qualified name. Example: T::SpecialA.'
tt(token tree): 单个语法树 (可以是任意的rust语法)'a single token tree.'
ty(type): 类型,语义层面的类型,如 i32, char 'a type. Examples: i32; Vec<(char, String)>; &T.'
item: 条目,function, struct, module, 'fn foo() { }; struct Bar;' 'an item. Examples: fn foo() { }; struct Bar;.'
meta: 元条目 如#[...] and #![...], 'cfg(target_os = "windows")' 'a "meta item", as found in attributes. Example: cfg(target_os = "windows").'
stmt: 单条语句,如 let a = 42; 'a single statement. Example: let x = 3.'
rust的宏匹配以后再有其他宏进行匹配时传入的是AST node无法再进行细致的token匹配,因此在模块化的宏是困难的。
这里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了。
被宏匹配过的token tree中的匹配项就是一个整体(匹配中的匹配项),不能再拆卡匹配了,也就是说嵌套宏是无法进行再次拆开匹配的功能,只有token tree 才能拆开匹配
就好比 下面的 '3 + 5', 再直接用match_tokens 匹配,那还能拆开为a + b, 但经过 capture_then_match_tokens 匹配后就是个整体的expr,再去用match_tokens进行匹配也是不行的。
rust match 若只是匹配没有结构行为则不会move或者引用
当我们调用is_empty, self并不会move因为他只是匹配看看self是不是Entry::Empty类型,is_full也是,他是匹配的Entry::Full(..)类型,并没有move,等, Entry::Full(..) === Entry::Full(,,_),一个都不move或者引用,只有使用了self里的字段才会move或者引用
rust macro
至此,由于输入中并不包含二元加的右手侧元素,你可能会以为,分析器将会放弃尝试这一规则,转而尝试下一条规则。实则不然:分析器将会panic并终止整个编译过程,返回一个语法错误。
由于分析器的这一特点,下面这点尤为重要:一般而言,在书写宏规则时,应从最具体的开始写起,依次写至最不具体的。
从上面可以看出token自左向右中序,AST先根 先序
绝对没有任何在上述位置以外的地方使用宏的可能。
macro的输入是single token tree即匹配的也是single token tree, 输出是AST, 也就是说不可以把一个一个宏的展开结果输入给另一个宏
rust中所有的宏的最终展开必须是一个完整的,有效的语法元素(比如表达式,条目等等)
如书中的例子
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:
按照上面所说的 所有的tokens都是token trees 大部分也都是叶子,只有 (). {}. []不是,因此 上面的那个表达式一共有 7 个 single token tree;
a, +, b, +, (c + d[0]), +, e
[rust 中的vector之一种值] // 待理解
The text was updated successfully, but these errors were encountered: