Rust中常量用let不用const是因为let 是函数式语言中的绑定(binding),而不是赋值(assignment)。let 这么强大的东西为什么不用呢,const,var 能不能玩匹配。当一个函数或方法返回一个 tuple,需要把它解析出来。
一、Rust中常量为什么用let不用const
Rust中常量用let不用const是因为let 是函数式语言中的绑定(binding),而不是赋值(assignment)。let 这么强大的东西为什么不用呢,const,var 能不能玩匹配。当一个函数或方法返回一个 tuple,需要把它解析出来。
作者:tennix
链接:https://www.zhihu.com/question/31135994/answer/57560660
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
fn f() -> (&str, i32) {}
let (a, b) = f()
let (mut a, b) = f()
let (_, b) = f()
let (ref a, b) = f()
如果返回的是一个结构体,可以这么玩
struct Point {
x: f64,
y: f64,
}
fn f() -> Point {}
let Point{x: a, y:b} = f();
let Point{x: mut c, y:_} = f();
let Point{x: _, y: ref d} = f();
如果用 const, var 应该怎么写上面这些呢
const a;
var b;
Point p = f(); //Tuple t = f();
a = p.x; // a = p.0;
b = p.y; // b = p.1;
另外还有 if let 和 while let 这样的东西,玩的也是模式匹配,直接把 Some 里面非空的东西抠出来使用,Simple, Clear, Powerful!
if let Some(x) = option {
foo(x);
} else {
bar();
}
while let Some(x) = option {
println!(“{}”, x);
}
另外 const 有必要么,写过 C++ 或 Java 大型项目应该体会到到处是 const/finally,之前有人统计过 Rust 项目里 。
let mut 与单 mut 的比例
(即mut和const的比例),其中单 let 是 let mut 的3倍,与其到处写 const 防止被修改,为什么不默认就是不可变 呢,这样可以省去许多击键数。
关于这个问题早先邮件列表里也有过很长很长的讨论,有兴趣的可以去看看。
Rust 也有 const,不过与其它语言中的不太一样,更像 C 中 define 定义的常量,因为会直接 inline 到使用的地方。
延伸阅读:
二、&mut T实现了move semantic 吗
fn main() {
let mut name = String::from(“TENX-S”);
let a = &mut name;
let b = a; // `a` has been moved!
add_string(a); // 爆炸
add_string(b);
add_string(b); // `b` has not been moved!
}
fn add_string(s: &mut String) {
s.push_str(“Rust”);
}回答问题之前,我们先说move是什么,简单一点就是如果一个类型没有实现Copy这个trait,那么把这个类型的变量赋给另一个变量或传递给一个函数时就会发生move,细节上来说,就是把右值的value赋给左值,然后invaildate右值的地址,使之不可访问;不过在TRPL中是用ownership解释的,本质是一样的。
不可变引用实现了Copy,所以不会因为赋值而发生move。
然而,可变引用不是Copy的,想想都知道,如果是Copy的,一个scope中就能轻松地写出多个指向同一个类型的可变引用,直接原地爆炸(
但是,我们又知道,没有实现Copy的类型在赋值和传递函数参数时都会发生move,那么例子中的b为什么没有move呢?
因为隐式重借用(implicitly reborrowed)取代了move,即对编译器来说:
add_string(y);
变成了:
add_string(&mut *y);
原始引用被解引用了,一个新的可变引用被创建了,这个新的引用被move进了函数内部,而原始引用在函数结束时被释放了。
然而,隐式重借用也是有适用范围的,即类型必须已知才可以,否则就会move,看下面这个例子:
fn bar<T>(_a: T, _b: T) {}
fn main() {
let mut i = 42;
let mut j = 43;
let x = &mut i;
let y = &mut j;
bar(x, y); // Moves x, but reborrows y.
let _z = x; // error[E0382]: use of moved value: `x`
let _t = y; // Works fine.
}
变量前用下划线表示不倾向于使用它,否则编译器会发出warning: unused variable …
x为什么被move了?因为函数参数此时未知,y为什么没被move,因为函数参数已知,发生隐式重借用。
如果你弄明白了上面所说的,请看下面这个例子:
struct Foo;
fn main() {
let a = &mut Foo;
a.mut_ref();
}
impl Foo {
fn mut_ref(&mut self) { }
}
变量a被声明为不可变的,然而,我们却获取了它的可变引用?是这样吗?
答案是否定的,我们并没有获得变量a的可变引用,解释如下:
我们都知道,其实&self是语法糖,所以
impl Foo {
fn mut_ref(&mut self) { }
}
其实相当于:
impl Foo {
fn mut_ref(self: &mut Self) { }
}
所以:
a.mut_ref();
其实是:
Foo::mut_ref(&mut *a);
整个过程中,并没有使用a的可变引用!