2016-12-18 3 views
0

Я, кажется, попал в дыру, известную как «борьба с заемщиком чека» на этом. У меня есть следующие функции:Модифицированная ссылка на кортеж в качестве входного параметра

fn draw_pair(decks: &(&mut Deck, &mut Deck)) -> (Card, Card) { 
    let (&mut p1, &mut p2) = decks; 

    (p1.draw_card(), p2.draw_card()) 
} 

Я получаю следующее сообщение об ошибке:

expected type: &(&mut Deck, &mut Deck) 
found type: (_, _) 

Идея заключается в том, чтобы взять Мутабельную Ссылку на содержание кортежа. Я не вижу причин мутировать сам кортеж. Эта функция будет работать в цикле.

Вместо этого я пытался написать let &(&mut p1, &mut p2) = decks;, но он говорит мне, что он не может выйти из заимствованного содержимого.

Вот функция, которая вызывает draw_pair:

fn play(decks: (Deck, Deck)) { 
    loop { 
     let cards = draw_pair(&decks); 
     // actual game not yet implemented 
    } 
} 

Это тоже дает мне ошибку, заявив, что ожидает &(&mut Deck, &mut Deck), но становится &(Deck, Deck).

+0

Вы передаете & (Deck, Deck) функцию draw_pair, а не ожидаемую & (& mut Deck, & mut Deck) , – SplittyDev

+0

@SplittyDev Я знаю об этом. –

+0

@SplittyDev данные, которые у меня под рукой, неизменяемы по умолчанию –

ответ

1

Всякий раз, когда вы хотите получить ссылки с помощью сопоставления с образцом и деструктурирующие, используйте ref instead of &. Вместо этого используйте let (ref mut p1, ref mut p2), и разыгрывают deck.

Необходимо отметить, что вы не можете мутировать неизменные данные. Вы можете использовать свои собственные изменяемые клоны или работать без мутации.Создание decks в play mutable - единственный способ получить изменяемые ссылки на внутренние данные в draw_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 
    } 
} 

Если decks пара вы получаете в play неизменен, нет никакого другого пути вокруг него, но и поддерживать свои собственные клонированные и изменяемые Deck сек как @wimh делает в своем ответе. Если вы хотите более точно создать свой собственный изменяемый клон, следующий лайнер поможет: &(&mut decks.0.clone(), &mut decks.1.clone())

0

Это первая ошибка:

8 |  let (&mut p1, &mut p2) = decks; 
    |   ^^^^^^^^^^^^^^^^^^ expected reference, found tuple 
    | 
    = note: expected type `&(&mut Deck, &mut Deck)` 
    = note: found type `(_, _)` 

Самый простой способ исправить, что разыменования правильный размер (*decks), но тогда вы получите другую ошибку:

8 |  let (&mut p1, &mut p2) = *decks; 
    |   ^^^^^-- 
    |   | | 
    |   | hint: to prevent move, use `ref p1` or `ref mut p1` 
    |   cannot move out of borrowed content 

Как намекали, используя ref исправляет это:

let (&mut ref p1, &mut ref p2) = *decks; 

Но нет никакой d полностью destructure левой стороны, вы можете также использовать

let (ref p1, ref p2) = *decks; 

Вот minimum implementation воспроизвести вашу проблему, с исправлением применяется:

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!"); 
} 

редактирование: здесь есть решение для play функции без изменения его подпись:

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{})); 
} 
+0

Я обновил свой вопрос –

+0

Требуется ссылка 'mut'. Это должно быть 'let (ref mut p1, ref mut p2)' – EvilTak

+0

@ElectricCoffee, лучше задать новый вопрос вместо того, чтобы добавлять к нему больше проблем, но я включил возможное решение для моего ответа. Поскольку я не знаю ваших точных требований, я не уверен, что это сработает для вас. Пожалуйста, обратите внимание на пример [Минимальный, полный и проверенный] (http://stackoverflow.com/help/mcve) пример, который воспроизводит вашу проблему в будущем. – wimh

1

Поскольку вы не можете выйти из заимствованных изменяемых ссылок, вы должны клонировать поля.

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) 
} 

Вот Playpen и here's a version, который сохраняет play подпись.

Честно говоря, я думаю, что в этом случае добавление нового типа для представления кортежа было бы более чистым и понятным решением.

В идеале я хотел бы сделать это так:

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 {}) 
} 
+0

Это не идеальное решение. Линия, которая заставляет все это работать, «пусть бат-колоды = колоды» - это плохой хак, которого следует избегать любой ценой. Это не влияет на такое маленькое приложение, но оно будет работать в многопоточном/параллельном сценарии. То, что является неизменным, не должно быть мутировано любой ценой. – EvilTak

+0

Как это можно избежать любой ценой? У вас есть пара , поэтому вы можете получить изменяемую ссылку на нее. Это никогда не вызовет никаких проблем. В многопоточном сценарии вы все равно должны его синхронизировать, используя ячейку или Mutex . В качестве альтернативы, вы можете изменить пар на парку & mut , и все будет хорошо. – SplittyDev