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对,这样您就可以了。