首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

【Rust每周一知】如何理解Rust中的可变与不可变

("{}, {}", r1, r2); let x = 1; let y = &mut x; // ERROR: 当有一个不可变值时,不能可变借用它 } Rust内存安全性基于以下规则...同时,相对于一般的静态借用,RefCell具有动态借用检查机制,使得编译器不会在编译期,而是在运行时做借用检查。 borrow()方法,不可变借用包裹值,可存在多个。...borrow_mut()方法可变借用包裹值,只能有一个,且借用不能可变借用。...(move || { let c = RefCell::new(5); let m = c.borrow(); let b = c.borrow_mut(); // ERROR: 借用不能可变借用...通常情况下,共享不可变可变共享。 内部可变性,单线程使用Cell 和RefCell 。 内部可变性,多线程使用Mutex,RwLock(后续)。

1.9K20

Rust 概念解惑 | Deref vs AsRef vs Borrow vs Cow

因为 Rust 所有权语义是贯穿整个语言特性,所以 拥有(Owner)/不可变借用(&T)/可变借用(&mut T)的语义 都是配套出现的。...一个类型通过实现 Borrow,在 borrow()方法中提供对 T 的引用/借用,表达的语义是可以作为某个类型 T借用,而非转换。一个类型可以自由地借用为几个不同的类型,也可以用可变的方式借用。...Borrow 是对借用数据的一种限制,并且配合额外的trait来使用,比如示例中的 Hash 和 Eq 等。 再看一个示例: // 这个结构体能不能作为 HashMap 的 key?...Cow 主要功能: 作为智能指针,提供对此类型实例的透明的不可变访问(比如可直接调用此类型原有的不可变方法,实现了Deref ,但没实现 DerefMut); 如果遇到需要修改此类型实例,或者需要获得此类型实例的所有权的情况...它有以下几个要点需要掌握: Cow 能直接调用 T 的不可变方法因为 Cow 这个枚举,实现了 Deref; 在需要修改T的时候,可以使用.to_mut()方法得到一个具有所有权的值的可变借用

2.9K30
您找到你想要的搜索结果了吗?
是的
没有找到

如何理解 rust 中的 Sync、Send?

锁不就是把 Sync 的类型变 Sync 的存在吗?...所以答案很明了了,如果 T Sync,就不能让多个线程同时拿到 T 类型对象的不可变引用。 并行读?内存不安全? 所以,并行只读会导致内存不安全吗?这似乎不符合直觉。那到底是啥原因呢?...所以,符合这个要求的类型有两种: 第一种类型你永远不能通过它的不可变引用改变它的内部,它所有的 pub field 都是 Sync 的,然后所有的以 &self 作为 receiver 的 pub method...第二种类型当然所有的 pub field 都得是 Sync 的,但它可能存在以 &self 作为 receiver 的 pub method 能改变自身(或返回内部可变引用),只不过这些方法本身得自己保证多线程访问的安全性...至于可变引用,因为永远只同时存在一个可变引用,且其不与不可变引用共存,所以以可变引用为 receiver 的方法永远是线程安全的,无需其它的约束。

2.8K51

【翻译】Rust生命周期常见误区

因为这意味着我们告诉Rust,这个方法可变借用这个结构体直到整个结构体生命周期结束。...这也就告诉Rust的借用检查器最多只允许 some_method 调用一次, 在这之后这个结构体将会被永久性地可变借用走,也就变得不可用了。...误解推论 重新借用一个引用会终止它的生命周期并且开始一个新的 你可以向一个接收共享引用的函数传递一个可变引用,因为Rust会隐式将可变引用重新借用为不可变引用: fn takes_shared_ref...这种重新借用出来的共享引用非常难用,因为不能与其它共享引用共存。它有着可变引用和不可变引用的所有缺点,却没有它们各自的优点。...// 将self的可变引用降级为T的共享引用 fn other_method(&mut self) -> &T; } 即使你避免了函数和方法签名中的重新借用,Rust仍然会自动隐式重新借用

1.5K20

2023学习日志

实现Drop trait需要实现其drop方法,该方法在变量离开时调用,完成指定的一些操作。...>Weak指针为弱引用,可以通过Rc::downgrade方法返回一个*Weak指针,不会导致引用计数发生变化,不会对堆上数据的清理产生影响因为Weak引用的值可能已经丢弃了,因此需要在使用...因为RefCell允许在运行时检查借用规则,因此可以在RefCell自身不可变的情况修改其内部的值。...可变借用计数规则类似不可解压计数规则。与编译时借用规则相同:RefCell在任何时刻只允许存在多个不可变借用或一个可变借用。...示例: impl Messenger for MockMessenger { fn send(&self, message: &str){ //代码将报错,不能同时存在两个可变借用

13110

一起学Rust-引用 · 借用

("{}", a); 二、借用 借用是与引用密不可分的,当把引用用作方法的参数,则称之为借用(borrow)。 Rust的编译器内存在一个借用检查器,检查的就是上一小节的引用规则。...借用使用场景:当方法不需要获取输入参数的所有权,则需要使用借用。如下例子中borrow_fn并不需要获取n的所有权,仅仅使用值进行判断。...("{}", num); } 借用时,可变引用可以作为可变引用参数,反之则不行: fn mut_borrow_value(n: &i32) { if *n > 2 { println...而需要获取解构的引用时则情况不太一样,可以使用ref获取解构内成员的不可变引用和可变引用: struct Rect { w: i32, h: i32, } fn main() {...("{}, {}", ww, h); } 传说 有一个瞎编古老的传说:很久很久以前,唐老大与唐老二、唐老三、唐老四江湖人称唐氏四兄弟。

1K10

实现一个线程安全且迭代器可以保存的链表

所有对象都只能有一个可变借用或多个不可变借用。但是可变借用和多个不可变借用直接不能共存,相当于是编译期的读写锁。 借用可以理解为不管理生命周期的引用。...所以就不能把这个游标保存起来以后用。那可不可以包一层 RefCell 来运行时借用,然后只用不可变的 Cursor 呢?...包括标准库实现里的 Iter 和 Cursor 里都存了 len 和提供方法获取后续有多少可用元素都是依赖与此。但是我们这里分离了迭代器和容器的生命周期,就不能简单地这么声明了。...因为我们解绑了迭代器和容器的生命周期,那么就无法在编译期保证多线程的场景下对节点的修改操作互相冲突,这里的锁的作用其实也是为了支持多线程修改容器。...但是这样感觉会提供整个库使用的难度和复杂度,而且也线程安全。要线程安全就得也套个 RwLock 或者 Mutex , 这样开销高不说也不能覆盖实际使用的场景。所以最终还是决定套了。

1.2K20

rust的内存管理

非堆内存可以使用copy,隐式转化,clone需要显示调用 关于借用的规则,使用& 一个引用的生命周期不能超过其引用的时间 如果存在一个可变借用,不允许存在其他值 如果不存在可变借用,允许存在多个不可变借用...借用规则方法类型 &self &mut self self 生命周期,一般手动输入的比较少 使用'修饰 'static 运行期间都有效 生命周期规则 输入型生命周期 输出型生命周期 多个生命周期 Rust...的指针类型 引用 &T不可变应用 &mut T可变引用 原始指针 *const T 不可变的指针 *mut T可变指针 智能指针 Drop释放前调用方法 Deref,DerefMut 智能指针实现的两个特征...,多个可变引用 RefCell 内部的可变引用,不需要实现copy use std::panic; use std::cell::Cell; #[derive(Debug)] struct...B { item: Box } #[derive(Clone, Debug)] struct C { i: u32 } #[derive(Debug)] struct

69610

Rust入门之严谨如你

3.3,不能同时有两个可变借用 为了避免产生数据竞争,Rust直接在编译阶段禁止了两个可变借用的同时存在(不用担心,并发有其他安全的办法实现),先看这段代码: fn mut_borrow_var_twice...因为46行改值可能影响你原先对47行及其后的预期。 事实上,如果可变借用不是交叉,编译器会放行,比如:交换46、47行的两次借用。具体可以自行编译试一下。...3.4,不能同时有可变借用与不可变借用 下面将展示Rust更严格的一面,不仅不能同时出现两个不可变借用可变与不可变借用不能交叉出现,本质还是编译器“担心程序员没有注意到发生了交叉使用”,从而潜在产生...3.5,严谨性不能覆盖的一面 前面两节介绍了编译器对于同时有两个借用的合法性检查,现在我们看一个同时有两个可变借用,但编译器无法覆盖的情况。...5,其他 1,Rust不会因为你永远没有调用到某些代码,而不去对其中的代码进行编译检查。比如本文的所有实例,都没有main调用,却被进行了编译检查。

1.7K175

实现一个线程安全且迭代器可以保存的链表

所有对象都只能有一个可变借用或多个不可变借用。但是可变借用和多个不可变借用直接不能共存,相当于是编译期的读写锁。 借用可以理解为不管理生命周期的引用。...所以就不能把这个游标保存起来以后用。那可不可以包一层 RefCell 来运行时借用,然后只用不可变的 Cursor 呢?...因为 IterMut 或 CursorMut 只要能创建出来,那之前一定没有不可变借用了。那么对 len 字段的修改就有且仅有最后创建出来的这个 IterMut 或 CursorMut。...因为我们解绑了迭代器和容器的生命周期,那么就无法在编译期保证多线程的场景下对节点的修改操作互相冲突,这里的锁的作用其实也是为了支持多线程访问容器。...但是这样感觉会提供整个库使用的难度和复杂度,而且也线程安全。要线程安全就得也套个 RwLock 或者 Mutex , 这样开销高不说也不能覆盖实际使用的场景。所以最终还是决定套了。

61620

rust智能指针

如果 deref 方法直接返回一个值,而不是引用,那么该值的所有权将被转移给调用者,而我们希望调用者仅仅只是 *T 一下,就拿走了智能指针中包含的值。...这段代码中: Drop 特征中的 drop 方法借用了目标的可变引用,而不是拿走了所有权。...原因在于,Rust 自动为几乎所有类型都实现了 Drop 特征,因此就算你手动为结构体实现 Drop,它依然会调用默认实现的 drop 函数,同时再调用每个字段的 drop 方法。...事实上,Rc 是指向底层数据的不可变的引用,因此你无法通过它来修改数据,这也符合 Rust 的借用规则:要么存在多个不可变借用,要么只能存在一个可变借用。...RefCell 简单总结 与 Cell 用于可 Copy 的值不同,RefCell 用于引用 RefCell 只是将借用规则从编译期推迟到程序运行期,并不能帮你绕过这个规则 RefCell 适用于编译期误报或者一个引用在多处代码使用

1.1K30

2023学习日志

rust测试驱动开发的思想编写失败测试编写使测试成功的代码重构之前的代码重复以上步骤环境变量可以通过std::env::var函数获取环境变量,该函数的返回结果为Result类型,可以通过is_ok方法来判断环境变量是否设置...当环境变量设置时,is_ok方法返回true,否则返回false。示例:let tem = std::env::var("TEST").is_ok(); 标准错误输出可以使用eprintln!...在rust中,闭包为一个可以保存在变量中或作为参数传递的匿名函数。闭包与类型注解不同与普通函数,编译器可以通过编译器推断参数及返回值类型,因此可以标明参数及返回值类型(也可自己加上类型声明)。...,仅对其进行读取操作捕获可变借用即对捕获到的变量进行修改,但不改变所有权值得注意的是,可变借用与其他借用不能同时存在,因此闭包定义与调用之间的作用域中不能有其他不可变借用,如,不能在闭包定义与调用之间的作用域出现捕获到的变量的输出语句...因为若只捕获不可变借用,主线程可能在新线程运行前将该变量丢弃,导致线程的不可变引用失效。

10700

《Rust for Rustaceans》 样章试译 | 第二章 Rust 基础

例如,不能有两条并行的流对值进行可变访问。也不能有一条流借用一个值,但没有流拥有这个值。清单 2-2 展示了这两种情况。...(*y, 42); // (4) // 清单 2-2:借用检查器将捕获的非法流 首先,在 x 初始化之前,我们不能使用它,因为我们没有地方可以画流。...相反,所有的方法要么完全替换该值,要么返回所含值的一个副本。因为不存在对内部值的引用,所以总是可以移动它。而且,由于 Cell 不能跨线程共享,即便可变是通过共享引用发生的,内部值也不会被并发改变。...然后借用检查器在(3)处打印语句中发现了r使用。它回到了(1)处的路径,发现没有冲突在使用((2)并没有在该路径上),所以它也接受了这个使用。...这些引用需要有一个生存期,当它们用于该类型的各种方法时,借用检查器可以凭此检查它们的有效性。如果你想让类型的某个方法返回比自己的引用存活期更长的引用,尤其需要如此。

5.3K30

Rust 让人迷惑的 “借用

借用规则 引用 (reference) 获取所有权,坚持单一所有者和单一职责,解决了共享访问障碍。...按引用传递对象的方式称作借用 (borrow), 这比转移所有权更有效 一个引用的生命周期,一定不会超过其引用的时间。...这显而易见的,为了防止悬垂引用 如果存在一个值的可变借用,那么在该借用作用域内,不允许有其它引用(读或写) 没有可变借用的情况下,允许存在多个对同一值的不可变借用 fn main() { let...owner a, 这时报错 原因在于,a_ref 是可变借用,在他的作用域内,不允许存在其它不可变借用或是可变借用,这里 println!...说白了,就是内存谁负责释放的问题 还有一个是类型的方法,第一个参数要写成 &self 或是 &mut self, 如果写成 self 那么函数就会捕捉类型的所有权,函数执行一次,就无法再使用这个类型 struct

41520

Rust 关联常量,泛型结构体,内部可变

(这里不需要容量的概念,因为 Polynomial 不能动态增长。)...但有一个问题:File 必须是可变的。所有用于写入的方法都需要一个可变引用。 这种情况经常发生。我们需要一个不可变值(SpiderRobot 结构体)中的一丁点儿可变数据(一个 File)。...ref_cell.borrow_mut()(可变借用) 返回一个 RefMut,它本质上是对 ref_cell 中值的可变引用。 如果该值已被借出,则此方法会 panic,详细信息稍后会解释。...ref_cell.try_borrow()(尝试借用)和 ref_cell.try_borrow_mut()(尝试可变借用) 行为与 borrow() 和 borrow_mut() 一样,但会返回一个...这样,在你尝试借用 w 之前,r 已经丢弃了。 这很像普通引用的工作方式。唯一的区别是,通常情况下,当你借用一个变量的引用时,Rust 会在编译期进行检查,以确保你在安全地使用该引用。

6910

一起长锈:4 默认不可变的变量绑定与引用(从Java与C++转Rust之旅)

因为借用规则,引用的使用比指针更受限。” “比方说,在同一作用域内,你不能拥有一个值的多个可变引用。” “如果你需要安全的修改和访问数据,那引用就是首选。”...“ ”其中 &i32 表示 x 是一个指向 i32 类型整数的不可变引用。“ ”在 Rust 中,不可变引用意味着你不能通过这个引用修改它所指向的数据。“ ”参数 x 只能读取,不能修改。...赋值涉及所有权或范围的概念。值被复制到预分配的内存中 内存管理 涉及所有权,借用和生命周期的明确概念。内存管理与变量绑定有关 由垃圾收集管理。...支持不可变 (const T*) 和可变 (T*) 引用。 所需库支持 标准库中包含丰富的函数和宏来支持安全的引用操作。 标准库中包含专门支持引用操作的特殊库,引用视为对象的默认行为。...引用操作通常直接影响性能,因为Java虚拟机进行优化。 性能优良,指针操作直接且快速,但风险较高。 内存管理方式 借助所有权系统自动管理内存,无需手动释放内存。

14743

4.MOVE从入门到实战-可编程Resource-如何使用Resource

移动 Resource 到 account 需要使用内建函数 move_to,需要 signer 作为第一个参数,T 作为第二个参数。...不可变借用 borrow_global 可变引用(&mut)和不可变的引用(&) // sources/Collection.move module std::Collection { use...另一个结论:由于 Borrow检查,你不能返回对 Resource 的引用或对其内容的引用(因为对 Resource 的引用将在函数作用域结束时消失)。...acquires 使用方法如下: fun (): acquires T, T1 ... { 可变借用 borrow_global_mut 要获得对...因为脚本上下文不允许你对结构体或 Resource 做任何事情,除非 Resource 模块中定义了操作 Resource 公开方法,否则只能将其传递到其它地方。

50840

第5章 | 对值的引用,使用引用,引用安全

(); } } 于是我们需要传入一个: sort_works(&mut table); 这种可变借用使 sort_works 能够按照向量的 sort 方法的要求读取和修改此结构。...运算符的代码,因此它也能利用这种隐式解引用的方式。 在进行方法调用时,. 运算符也可以根据需要隐式借用对其左操作数的引用。...例如,Vec 的 sort 方法就要求参数是对向量的可变引用,因此这两个调用是等效的: let mut v = vec!...变量 r 和 x 都有各自的生命周期,从它们初始化的时间点一直延续到足以让编译器断定不再使用它们的时间点。第三个生命周期是引用类型,即借用了 x 并存储在 r 中的引用类型。...来自 Rust 的错误消息其实建议了另一种方法,这种方法更通用: help: consider introducing a named lifetime parameter | 7 | struct

3610
领券