Rust 对元组的可变引用作为输入参数
我似乎掉进了这个被称为“与借钱人搏斗”的洞里。我有以下功能:Rust 对元组的可变引用作为输入参数,rust,borrow-checker,Rust,Borrow Checker,我似乎掉进了这个被称为“与借钱人搏斗”的洞里。我有以下功能: fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (Card, Card) { let (&mut p1, &mut p2) = decks; (p1.draw_card(), p2.draw_card()) } 我得到以下错误: 预期类型:&(&mut-Deck,&mut-Deck) 找到的类型:(,) 其思想是对元组的
fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (Card, Card) {
let (&mut p1, &mut p2) = decks;
(p1.draw_card(), p2.draw_card())
}
我得到以下错误:
预期类型:&(&mut-Deck,&mut-Deck)
找到的类型:(,)
其思想是对元组的内容进行可变引用。我认为没有理由改变元组本身。此函数将在循环中运行
我尝试过编写let&(&mutp1,&mutp2)=decks代码>相反,但它告诉我它不能移出借用的内容
下面是调用draw\u pair
的函数:
fn play(decks: (Deck, Deck)) {
loop {
let cards = draw_pair(&decks);
// actual game not yet implemented
}
}
这也给了我一个错误,说它期望&(&mut-Deck,&mut-Deck)
,但得到&(Deck,Deck)
,这是第一个错误:
8 | let(&mut p1,&mut p2)=甲板;
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^应为引用,找到元组
|
=注:预期类型`&(&mut-Deck,&mut-Deck)`
=注意:找到类型`(,)`
最简单的修复方法是取消对正确大小的引用(*decks
),但随后会出现另一个错误:
8 | let(&mut p1,&mut p2)=*甲板;
| ^^^^^--
| | |
||提示:要防止移动,请使用'ref p1'或'ref mut p1'`
|无法移出借用的内容
正如使用ref
所提示的,修复了以下问题:
let (&mut ref p1, &mut ref p2) = *decks;
但是没有必要完全解构左侧,您也可以使用
let (ref p1, ref p2) = *decks;
下面是一个用于重现您的问题并应用修复程序的示例:
struct Card{}
struct Deck{}
impl Deck {
fn draw_card(&self) -> Card { Card {}}
}
fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (Card, Card) {
let (ref p1, ref p2) = *decks;
(p1.draw_card(), p2.draw_card())
}
fn main() {
println!("Hello, world!");
}
编辑:以下是一个解决方案,用于您的播放
功能,无需修改其签名:
struct Card{}
#[derive(Clone)]
struct Deck{}
impl Deck {
fn draw_card(&self) -> Card { Card {}}
}
fn play(decks: (Deck, Deck)) {
loop {
let (ref deck1, ref deck2) = decks;
let mut deck1 = deck1.clone();
let mut deck2 = deck2.clone();
let decks = (&mut deck1, &mut deck2);
let cards = draw_pair(&decks);
// actual game not yet implemented
}
}
fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (Card, Card) {
let (ref p1, ref p2) = *decks;
(p1.draw_card(), p2.draw_card())
}
fn main() {
play((Deck{}, Deck{}));
}
由于无法移出借用的可变引用,因此必须克隆字段
fn main() {
play((&mut Deck(0), &mut Deck(0)));
}
#[derive(Clone)]
struct Deck(i32);
fn play(decks: (&mut Deck, &mut Deck)) {
let cards = draw_pair(&decks);
}
fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (i32, i32) {
let mut p1 = decks.0.clone();
let mut p2 = decks.1.clone();
(0, 0)
}
这是一个保留播放
签名的and
老实说,我认为在这种情况下,添加一个新类型来表示元组将是一个更干净、更可读的解决方案
理想情况下,我会这样做:
struct Deck {}
struct Card {}
#[derive(Debug)]
struct Pair<T> {
first: T,
second: T,
}
impl<T> Pair<T> {
pub fn new(first: T, second: T) -> Pair<T> {
Pair { first: first, second: second }
}
}
fn play(decks: Pair<Deck>) {
let mut decks = decks;
let cards = draw_pair(&mut decks);
}
fn draw_pair(decks: &mut Pair<Deck>) -> Pair<Card> {
Pair::new(Card {}, Card {})
}
struct Deck{}
结构卡{}
#[导出(调试)]
结构对{
第一:T,,
第二:T,
}
impl对{
pub fn new(第一个:T,第二个:T)->成对{
对{first:first,second:second}
}
}
fn游戏(套牌:双人){
让多个甲板=甲板;
let cards=抽牌对(多组牌组和多组牌组);
}
fn绘图对(甲板:&mut对)->对{
对::新(卡{},卡{})
}
无论何时,只要您想使用模式匹配和分解来获取引用,请使用。改为使用let(ref mut p1,ref mut p2)
,并取消引用deck
您必须注意,您不能改变不可变的数据。您可以使用自己的可变克隆,也可以不进行变异。在play
mutable中设置deck
,是获取draw\u pair
中内部数据的可变引用的唯一方法。以下代码解决了您的问题:
fn draw_pair(decks: &mut (Deck, Deck)) -> (Card, Card) {
let (ref mut p1, ref mut p2) = *decks;
(p1.draw_card(), p2.draw_card())
}
fn play(mut decks: (Deck, Deck)) {
loop {
let cards = draw_pair(&mut decks);
// actual game not yet implemented
}
}
如果您在play
中收到的Deck
对是不可变的,那么除了像@wimh在他的回答中那样维护您自己的克隆和可变Deck
s之外,别无其他办法。如果您想更简洁地创建自己的可变克隆,以下一行代码将有所帮助:&(&mut Deck.0.clone(),&mut Deck.1.clone())
您正在向绘图对函数传递一个&(Deck,Deck),而不是预期的&(&mut Deck,&mut Deck)@SplittyDev我知道这一点。@SplittyDev默认情况下,我手头的数据是不可变的。我刚刚更新了我的答案,以包含更好的代码版本,而不包含丑陋的克隆和元组引用。需要mut
引用。它应该是let(ref mut p1,ref mut p2)
@最好是问一个新问题,而不是增加更多的问题,但我的答案中包含了一个可能的解决方案。因为我不知道你的确切要求,我不确定它是否适合你。请考虑包括一个在将来重现你的问题的例子。我知道,坏习惯。但是我想我应该把它加上去,因为它和前面的问题有关。有人问我是怎么用的,这就是为什么。在不修改类型的情况下,真的没有更简单的方法吗?尽管这不是一个理想的解决方案。让一切正常工作的那一行是一个糟糕的黑客行为,应该不惜一切代价避免。在这样一个小的应用程序中,这并没有什么区别,但在多线程/并发场景中会有区别。不可改变的东西不应该不惜任何代价进行变异。这是什么东西应该不惜一切代价避免?您拥有该对,因此可以获得对它的可变引用。这永远不会引起任何问题。在多线程场景中,无论如何都要使用单元格或互斥来同步它。或者,您可以将这对更改为a&mut对,这样您就可以了。