标签:编程语言 rust 生命期 安全
5.11 可变性
可变性,就是改变某些值的能力,Rust语言和其他语言有很大的区别.第一点就是Rust默认是不可变的:
let x = 5;
x = 6; // error!
我们可以引入mut关键字来增加可变性:
let mut x = 5;
x = 6; // no problem!
这是一个可变绑定.当一个绑定时可变的时候,你可以改变绑定指向的值.上例中,x的值没有太大变化,但是绑定从一个i32转移到了另一个i32上.
如果你需要改变绑定的值,你需要一个一个可变引用:
let mut x = 5;
let y = &mut x;
y是一个不可变绑定,它绑定到了一个可变引用上,也就是说你不能把y绑定到其他值上(
y = &mut z),但是你可以修改y绑定的对象的值(*y = 5).差别很微妙.当然你也可以同时声明他们两:
let mut x = 5;
let mut y = &mut x;
现在你可以把y绑定到其他对象上,y指向的对象的值也可以被修改.
mut是模式的一部分,你可以这样:
let (mut x, y) = (5,6);
fn foo(mut x: i32) {
5.11.1 内部和外部可变性
然而,当我们说某东西是不可变的时候,并不是说他不能被改变:我们是说它具有外部可变性.看一下Arc<T>的例子:
use std::sync::Arc;
let x = Arc::new(5);
let y = x.clone();
当我们调用clone()函数时,Arc<T>需要更新它的引用计数.而我们并没使用任何mut,x是一个不可变的绑定,我们也没有使用&mut 5或其他的什么.那么谁给了它可变性?
为了理解这个,我们需要回到Rust设计哲学的核心内容,内存安全,以及Rust提供内存安全的机制,所有权系统,以及更具体的,借用:
你可以拥有1个或多个下面两种类型的借用,但是不能同时拥有:
- 1个或多个引用(&T)
- 一个可变的引用(&mut T)
所以,那就是真实的不可变性的定义:它拥有两个指针的的时候安全吗?在Arc<T>的例子中,是的:可变性完全包含在结构体自身当中.他不是面向用户的.因此,它通过clone()交出了&T.但是,如果它交出了&mut T,那就糟糕了.
其他类型,例如std::cell模块中的类型,有相反的一面:内部可变性.例如:
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
RefCell通过borrow_mut()方法交出了自己内部的&mut引用.这个不是不安全么?如果我们这样:
use std::Cell:RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
let z = x.borrow_mut();
在运行时,这就会panic.RefCell做了这些:在运行时,如果Rust的借用规则被违反了,那么它会迫使程序panic.这会带领我们注意到另一个Rust的可变性的规则.我们先来看一下.
局部可变性(Field-level mutability)
可变性是借用(&mut)和绑定(let mut)的一个特性.你不能持有一个结构体,它有一个可变成员和一个不可变成员:
struct Point {
x: i32,
mut y: i32, // nope
}
一个结构体的可变性在它的绑定中:
struct Point {
x: i32,
y: i32,
}
let mut a = Point { x: 5, y: 6 };
a.x = 10;
let b = Point { x: 5, y: 6};
b.x = 10; // error: cannot assign to immutable field `b.x`
然而,通过Cell<T>,你可以改变成员变量的可变性:
use std::cell::Cell;
struct Point {
x: i32,
y: Cell<i32>,
}
let point = Point {x: 5, y: Cell::new(6) };
point.y.set(7);
println!("y: {:?}", point.y);
这会打印 y: Cell {value: 7}.我们成功的更新了y的值.
Rust中文翻译30
标签:编程语言 rust 生命期 安全
原文地址:http://blog.csdn.net/zcmit/article/details/46955067