我有以下代码:
use std::collections::{HashMap, HashSet};
fn populate_connections(
start: i32,
num: i32,
conns: &mut HashMap<i32, HashSet<i32>>,
ancs: &mut HashSet<i32>,
) {
let mut orig_conns = conns.get_mut(&start).unwrap();
let pipes = conns.get(&num).unwrap();
for pipe in pipes.iter() {
if !ancs.contains(pipe) && !orig_conns.contains(pipe) {
ancs.insert(*pipe);
orig_conns.insert(*pipe);
populate_connections(start, num, conns, ancs);
}
}
}
fn main() {}
逻辑不是很重要,我正在尝试创建一个本身并遍历管道的函数。
我的问题是这不能编译:
error[E0502]: cannot borrow `*conns` as immutable because it is also borrowed as mutable
--> src/main.rs:10:17
|
9 | let mut orig_conns = conns.get_mut(&start).unwrap();
| ----- mutable borrow occurs here
10 | let pipes = conns.get(&num).unwrap();
| ^^^^^ immutable borrow occurs here
...
19 | }
| - mutable borrow ends here
error[E0499]: cannot borrow `*conns` as mutable more than once at a time
--> src/main.rs:16:46
|
9 | let mut orig_conns = conns.get_mut(&start).unwrap();
| ----- first mutable borrow occurs here
...
16 | populate_connections(start, num, conns, ancs);
| ^^^^^ second mutable borrow occurs here
...
19 | }
| - first borrow ends here
我不知道如何让它发挥作用。一开始,我正在尝试将HashSet
存储在HashMap
(orig_conns
和pipes
)中。
Rust不会让我同时拥有可变和不可变的变量。我有点困惑,因为这将是完全不同的对象,但我想如果&start
== &num
,那么我会对同一个对象有两个不同的引用(一个是可变的,一个是不可变的)。 / p>
好的,但是我怎么能实现这个目标呢?我想迭代一个HashSet
并阅读和修改其他的HashSet
。我们假设它们不会是$("#btn1").click(myFunction);
。
答案 0 :(得分:9)
如果您可以更改数据类型和功能签名,则可以使用RefCell
创建interior mutability:
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
fn populate_connections(
start: i32,
num: i32,
conns: &HashMap<i32, RefCell<HashSet<i32>>>,
ancs: &mut HashSet<i32>,
) {
let mut orig_conns = conns.get(&start).unwrap().borrow_mut();
let pipes = conns.get(&num).unwrap().borrow();
for pipe in pipes.iter() {
if !ancs.contains(pipe) && !orig_conns.contains(pipe) {
ancs.insert(*pipe);
orig_conns.insert(*pipe);
populate_connections(start, num, conns, ancs);
}
}
}
fn main() {}
请注意,如果start == num
,线程将会发生混乱,因为这是尝试同时具有对同一HashSet
的可变和不可变访问。
RefCell
根据您的确切数据和代码需求,您还可以使用Cell
或atomics之类的类型。它们的内存开销低于RefCell
,对codegen的影响很小。
答案 1 :(得分:3)
如果可以保证两个索引不同,则可以使用不安全的代码并避免内部可变性:
HashMap
此代码尝试多加注意。一个断言强制了以下事实:两个键是不同的,并且我们显式地将生存期添加到返回的变量中。
在盲目使用此解决方案之前,您应该了解不安全代码的细微差别。
请注意,此功能不会试图解决原始问题,这比验证两个索引不相交要复杂得多。原始问题要求:
RefCell
,这会使先前级别中的任何现有引用无效。使用类似#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
string item = "";
ifstream fin;
double tgross = 0;
double tnet = 0;
double hourly;
double hours;
double taxrate;
double net;
string fileName = "payroll.txt";
fin.open("payroll.txt");
if(!fin.is_open())
{
void instructions()
{
cout << "This payroll program calculates an individual employee pay and";
cout << "\ncompany totals using data from a data file payroll.txt.\n";
cout << "\n\nA payroll report showing payroll information ";
cout << " is displayed.\n\n";
}
void reportTitle()
{
cout << setprecision(2) << fixed << showpoint << left
<< setw(20) << "Employee" << setw(10) << "Hourly" << setw(10) << "Hours"
<< setw(10) << "Tax" << setw(10) << "Gross" << setw(10) << "Net" << endl;
cout << setw(20) << "Name" << setw(10) << "Rate" << setw(10) << "Worked"
<< setw(10) << "Rate" << setw(10) << "Amount" << setw(10) << "Amount" << endl;
}
}
while(!fin.eof())
{
getline(fin,item,'#');
fin >> hourly >> hours >> taxrate;
double calculateGross(double hours, double hourly)
double calculateNet(double grosspay, double netpercent)
{
return grosspay - grosspay*netpercent/100.0;
}
void displayEmployeeInfo(const string &, double, double, double, double, double)
{
tgross += grosspay;
tnet += net;
}
}
void totalAmounts (double tgross, double tnet)
{
cout << "Totals" << setprecision(2) << fixed << showpoint << right
<< setw(50) << tgross << setw(10) << tnet << endl;
}
fin.close();
}
之类的方法来确保您不会触发内存不安全的情况更为简单。