Rust中文翻译30

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的值.

时间: 2024-08-01 01:38:45

Rust中文翻译30的相关文章

Rust中文翻译19

我们来讨论一下迭代器. 还记得Rust的for循环么?有一个例子: for x in 0..10 { println!("{}", x); } 现在你更了解Rust了,我们可以讨论它的工作细节了.区间(Ranges)(0..10)就是迭代器.一个迭代器可以重复的调用.next()方法,然后给我们返回一个序列. 像这样: let mut range = 0..10; loop { match range.next() { Some(x) => { println!("{}

Rust中文翻译7

去台湾玩儿了一个礼拜,赶紧回来继续翻译吧! 3.1.5 循环 Page 38 loop关键字可以实现一个无限循环.让我们来加入一个循环: extern crate rand; use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { println!("Guess the number!"); let secret_number = rand::thread_rng().gen_range(1, 101); prin

Rust中文翻译29

5.10 生命期 本节是Rust三处描述所有权系统的其中之一.所有权是Rust最独特和引人注目的特性,这也是Rust程序员必须熟悉的一个特性.所有权使Rust得以实现它最大的设计目标,内存安全.这里有一些不同的概念,每一个都有自己的章节: 所有权,你正在读的 借用(borrowing, 5.9), 以及它的关联特性'引用' 生命期(5.10),以及borrowing的高级特性 这三者是相关的,也是循序渐进的.你必须要完全理解这个三个部分. 5.10.1 元 在我们讨论细节之前,有两个关于所有权系

Rust中文翻译21

4.7 错误处理 有时候程序会发生错误.对于不可避免的事情发生时最好有一个计划来处理.Rust有丰富的处理错误的方法. 你的程序会出现两种类型的错误:失败和崩溃.我们先讨论两者的区别,然后讨论如何处理他们.然后,我们讨论把错误升级为崩溃. Page 107 4.7.1 失败和崩溃 Rust使用两种错误的类型:失败和崩溃.失败是一种可以被挽回的错误.崩溃却不行. "挽回"是什么意思呢?在多数情况下,很有可能会发生错误.例如,一个parse函数: "5".parse()

Rust中文翻译12

Page 63 我们已经学习了如何写一些Rust代码了.但是能写Rust代码和能写好的Rust代码又很大区别. 这一章讲述一些相对独立的指南,告诉你如何把的Rust代码更进一步.一些常用的模式和标准库会被提到.你可以随意安排阅读本章的顺序. 4.1 栈和堆 作为一个系统级别的语言,Rust可以在底层进行操作.如果你来自于高层语言,有一些系统编程概念你可能不太熟悉.最重要的就是内存中的栈和堆是如何工作的.如果你了解类C语言中栈的分配,这一章就是一个回顾.如果你不了解,你可以在本章学习这些概念了,但

Rust中文翻译28

5.9 引用和借用 本节是Rust三处描述所有权系统的其中之一.所有权是Rust最独特和引人注目的特性,这也是Rust程序员必须熟悉的一个特性.所有权使Rust得以实现它最大的设计目标,内存安全.这里有一些不同的概念,每一个都有自己的章节: 所有权,你正在读的 借用(borrowing, 5.9), 以及它的关联特性'引用' 生命期(5.10),以及borrowing的高级特性 这三者是相关的,也是循序渐进的.你必须要完全理解这个三个部分. 5.9.1 元 在我们讨论细节之前,有两个关于所有权系

Rust中文翻译17

4.2.4 文档测试 没有什么比带有示例的文档更好的了.也没有什么比不能工作的例子更糟的了,因为有可能文档中的代码已经修改了.为此,Rust支持自动测试我们示例代码.让我们看一个富有血肉的src/lib.rs的例子: //! The àdder` crate provides functions that add numbers to other numbers. //! //! # Examples //! //! ``` //! assert_eq!(4, adder::add_two(2)

Rust中文翻译15

大多数使用垃圾回收的语言都默认在堆上分配内存.这就意味着每个值都要装箱.有很多原因导致他们这样设计,但是这超出了本书的范围.同样,也有很多优化设计导致它并不是100%这样工作的.垃圾回收器宁愿选择在堆上分配内存,也不使用栈和Drop操作来释放内存. 4.1.7 该用哪一种呢? 所以当栈又快又好用的时候,为什么我们还需要使用堆呢?一个重要的原因是,栈只给你提供了LIFO语义来管理内存.堆分配却可以提供更加通用的和任意的顺序来使用内存,同时附带一些开销. 通常情况下,你应当使用栈,Rust默认就是如

Rust中文翻译20

Page 100 并发和并行在计算机科学中是非常重要的主题.在工业领域也很火.计算机如今有越来越多的核心,然而很多程序员还没有准备好使用它们. Rust安全的内存特性同样适用于并发存储.并发的Rust代码也是内存安全的,没有数据竞争.Rust的类型系统会保证这一点,给你提供了有利的帮助在编译时实现并发代码. 在我们开始讨论Rust的并发之前,我们需要理解一个很重要的事情:Rust是一个低级别语言,它的所有功能都是通过库来提供的,而不是语言自身.也就是说你不喜欢Rust处理并发的方式,你完全可以实