- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个带有 load_rom
方法的 CPU
结构:
use std::fs::File;
use std::io::{self, Read};
pub struct CPU {
pub mem: [u8; 4096],
V: [u8; 16],
I: u16,
stack: [u16; 16],
opcode: u16,
}
impl CPU {
pub fn new() -> CPU {
CPU {
mem: [0; 4096],
V: [0; 16],
I: 0,
stack: [0; 16],
opcode: 0,
}
}
pub fn load_rom(&self, filepath: &str) {
let mut rom: Vec<u8> = Vec::new();
let mut file = File::open(filepath).unwrap();
file.read_to_end(&mut rom);
for (i, mut byte) in rom.iter().enumerate() {
self.mem[i] = *byte;
}
}
}
fn main() {}
这会产生错误:
error: cannot assign to immutable indexed content `self.mem[..]`
--> src/main.rs:28:13
|
28 | self.mem[i] = *byte;
| ^^^^^^^^^^^^^^^^^^^
当我使用 let mut cpu = CPU::new();
创建 CPU 并将 &mut self
传递给 load_rom
方法时,一切正常。
如果我在创建时不使用 mut
,我会得到错误:
error: cannot borrow immutable local variable `cpu` as mutable
--> src/main.rs:10:2
|
9 | let cpu = CPU::new();
| --- use `mut cpu` here to make mutable
10 | cpu.load_rom("/Users/.../Code/Rust/chip8/src/roms/connect4.ch8");
| ^^^ cannot borrow mutably
我必须让 cpu
可变以便内部函数修改它自己的内容似乎不对。我真的必须将 cpu
声明为可变的吗?还是我遗漏了什么?
最佳答案
make
cpu
mutable in order for internal functions to modify its own contents
(强调我的)
Rust 是一种系统语言,这意味着它试图让您能够创建快速 和高效 代码。实现这一点的主要方法之一是提供对现有数据的引用而不是复制它。
Rust 也是一种安全语言,这(除其他事项外)意味着访问无效引用应该是不可能的。
要实现这两个目标,必须进行权衡。一些语言将安全检查转移到运行时,强制执行同步原语(例如互斥锁和 friend )或其他一些有趣的解决方案。有些语言完全避免了困惑,并选择禁止引用或不尝试保证安全。
Rust 与这些不同,它在编译时检查尽可能多的东西。这意味着编译器必须能够推断出内存片段何时何地可能发生变异。
如果它不知道这一点,那么您可能会获得对值中某些内容的引用,然后对该值调用使引用无效的变异方法。当您使用现在无效的引用时...BOOOOOM。您的程序在最好时会崩溃,或者在最坏时会泄漏信息或创建后门。
&mut self
向编译器表明此方法可能会改变其中的值。只有获取对已经可变的值的可变引用才有效,这由变量绑定(bind)上的 mut
关键字表示(此处为 mut cpu
)。
但是,这不仅仅是对编译器有用。了解正在更改的内容对程序员也非常有值(value)。大型系统中的可变性增加了难以推理的复杂性,并且被迫明确列出某些内容何时可变和不可变可能会提供很多信息并释放精神。
了解 Rust 应用的 rules for borrowing 也很有用。这些将您限制为以下之一:
* one or more references (`&T`) to a resource,
* exactly one mutable reference (`&mut T`).
简而言之,这可以概括为“别名 XOR 可变性”。
如果您的突变确实是内部的,那么您也可以使用 interior mutability ,例如使用 RefCell
或 Mutex
。您使用什么取决于您的需求和您想要存储的数据类型。
这些结构非常适合缓存等结构,您希望在其中“隐藏”外部的可变性。但是,这些也有局限性,因为必须缩短对数据的引用的生命周期,以继续提供“别名 XOR 可变性”保证以保持代码安全。
对于您的具体问题,我同意评论者的观点,即 load_rom
接受 &mut self
是有意义的。它甚至可以被简化:
pub fn load_rom(&mut self, filepath: &str) {
let mut file = File::open(filepath).unwrap();
file.read_exact(&mut self.mem);
}
您可能希望在加载之前将所有旧数据清零。否则,如果您加载比第一个小的第二个 ROM,则第一个 ROM 中的数据可能会泄漏到第二个 (an actual bug from older computers / operating systems)。
关于rust - 为什么我必须将一个变量声明为可变的,以便内部函数修改它自己的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42894646/
编辑备注 由于 Rust(版本:1.42)仍然没有稳定的 ABI ,推荐使用extern (目前相当于extern "C"(将来可能会改变))否则,可能需要重新编译库。 This article解释如
词法分析器/解析器文件位于 here非常大,我不确定它是否适合只检索 Rust 函数列表。也许我自己编写/使用另一个库是更好的选择? 最终目标是创建一种执行管理器。为了上下文化,它将能够读取包装在函数
我试图在 Rust 中展平 Enum 的向量,但我遇到了一些问题: enum Foo { A(i32), B(i32, i32), } fn main() { let vf =
我正在 64 位模式下运行的 Raspberry Pi 3 上使用 Rust 进行裸机编程。我已经实现了一个自旋锁,如下所示: use core::{sync::atomic::{AtomicBool
我无法理解以下示例是如何从 this code 中提炼出来的, 编译: trait A: B {} trait B {} impl B for T where T: A {} struct Foo;
在我写了一些代码和阅读了一些文章之后,我对 Rust 中的移动语义有点困惑,我认为值移动后,它应该被释放,内存应该是无效的。所以我尝试写一些代码来作证。 第一个例子 #[derive(Debug)]
https://doc.rust-lang.org/reference/types/closure.html#capture-modes struct SetVec { set: HashSe
考虑 const-generic 数据结构的经典示例:方矩阵。 struct Matrix { inner: [[T; N]; N] } 我想返回一个结构体,其 const 参数是动态定义的:
以下代码无法编译,因为 x在移动之后使用(因为 x 具有类型 &mut u8 ,它没有实现 Copy 特性) fn main() { let mut a: u8 = 1; let x:
我在玩 Rust,发现了下面的例子: fn main() { let mut x = [3, 4, 5].to_vec(); x; println!("{:?}", x); }
假设一个 Rust 2018 宏定义了一个 async里面的功能。它将使用的语法与 Rust 2015 不兼容。因此,如果您使用 2015 版编译您的 crate,那么宏中的扩展代码不会与它冲突吗?
假设我有一些 Foo 的自定义集合s: struct Bar {} struct Foo { bar: Bar } struct SubList { contents: Vec, }
代码如下: fn inner(x:&'a i32, _y:&'b i32) -> &'b i32 { x } fn main() { let a = 1; { let b
在lifetime_things的定义中,'b的生命周期比'a长,但实际上当我调用这个函数时,x1比y1长,但是这样可以编译成功: //here you could see 'b:'a means
我正在尝试检索 FLTK-RS Widget 周围的 Arc Mutex 包装器的内部值: pub struct ArcWidget(Arc>); impl ArcWidget{ pub
如下代码所示,我想封装一个定时函数,返回一个闭包的结果和执行时间。 use tap::prelude::Pipe; use std::time::{Instant, Duration}; pub fn
我想实现自己的通用容器,这是我正在使用的特征的片段: pub trait MyVec where Self: Default + Clone + IntoIterator, Self:
所需代码: 注释掉的块可以编译并工作,但是我想从嵌套的匹配样式转变为更简洁的函数链 async fn ws_req_resp(msg: String, conn: PgConn) -> Result>
我正在尝试编写一些代码,该代码将生成具有随机值的随机结构。对于结构,我具有以下特征和帮助程序宏: use rand::{thread_rng, Rng}; use std::fmt; pub trai
我有一个带有函数成员的结构: struct Foo { fun: Box, } type FooI = Foo; 这不起作用: error[E0106]: missing lifetime s
我是一名优秀的程序员,十分优秀!