2016-11-26 3 views
0

Учитывая следующий код (который не делает много еще):Несовпадение типов для возвращаемой структуры (ожидаемые <K, V>, нашли <&K, &V>)

use std::collections::BTreeMap; 
use std::iter::FromIterator; 

trait Node<K, V> { 
    fn split(&self) -> Split<K, V>; 
} 

#[derive(Debug, Copy, Clone)] 
pub struct Config { 
    data_b: usize, 
} 

struct Split<'a, K, V> { 
    left: Box<Node<K, V> + 'a>, 
    right: Box<Node<K, V> + 'a>, 
} 

#[derive(Debug)] 
pub struct DataNode<K, V> { 
    cfg: Config, 
    children: BTreeMap<K, V>, 
} 

impl<K: Clone + Ord, V: Clone> Node<K, V> for DataNode<K, V> { 
    fn split(&self) -> Split<K, V> { 
     let data_b = self.cfg.data_b; 

     Split { 
      left: Box::new(DataNode { 
       cfg: self.cfg.clone(), 
       children: BTreeMap::from_iter(self.children.iter().take(data_b)) 
      }), 
      right: Box::new(DataNode { 
       cfg: self.cfg.clone(), 
       children: BTreeMap::from_iter(self.children.iter().rev().take(data_b)) 
      }), 
     } 
    } 
} 

Компилятор выдает следующую ошибку:

error[E0308]: mismatched types 
    --> lib.rs:68:9 
    | 
68 |   Split { 
    |  ^expected type parameter, found &K 
    | 
    = note: expected type `Split<'_, K, V>` 
    = note: found type `Split<'_, &K, &V>` 

Я довольно новичок в Rust, поэтому я не уверен, что вызывает это. Чтобы быть абсолютно ясным, вопрос, который у меня есть, это не о чем сообщение об ошибке означает. Очевидно, это означает, что я не возвращаю правильный тип. Вопрос почему компилятор интерпретирует этот код Split {...} как код, который возвращает Split<'_, &K, &V>, когда я ожидаю, что это будет Split<'_, K, V>. Любое понимание очень ценится.

+0

Вы понимаете, [*, что ссылки *] (https://doc.rust-lang.org/stable/book/references- и-borrowing.html)? Вы понимаете, как работает ['BTreeMap :: iter'] (https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.iter)? IMO, сообщение об ошибке довольно просто - вы сказали, что собираетесь вернуть одно, но вы вернули что-то еще. Какая часть информации отсутствует, которую мы можем уточнить? – Shepmaster

+0

Я не сказал, что не понял сообщение об ошибке. Я не понимаю, почему * то, что я написал, приводит к 'Split <'_, &K, &V>'. Если это связано с тонкостью, которая приходит с использованием итератора, то да, это выше моего уровня знаний о Rust, и я был бы признателен за понимание. Лучшее, что я смог сделать, прежде чем приходить сюда, было проверить, что возвращать типы всего, но ничего не указывает на то, что ссылки вступают в игру. Поэтому каким-то образом компилятор чувствует себя вынужденным из-за некоторого требования сделать это, и я хотел бы понять, почему и как я могу получить то, что хочу, если это возможно. – neverfox

ответ

2

Ссылки приходят откуда вы итерацию на ребенка, чтобы построить новый BTreeMap:

BTreeMap::from_iter(self.children.iter().take(data_b)) 

Если вы посмотрите на iterator returned by BTreeMap::iter(), то Item тип:

type Item = (&'a K, &'a V) 

т.е. возвращает итератор пары ссылок на содержимое. Это имеет смысл, потому что вы не хотите перемещать элементы из карты при итерации или полагаться на Copy.

Это немного отличается от, например, Vec::iter(), являясь парой ссылок, а не ссылкой на пару. Это имеет смысл, поскольку ссылка на пару означает, что контейнер должен будет фактически содержать эти пары внутри (ограничивая внутреннюю структуру данных).

Проще всего клонировать ключ и значение:

BTreeMap::from_iter(self.children.iter() 
           .map(|(&a, &b)| (a.clone(), b.clone())) 
           .take(data_b)) 
+0

Спасибо за четкое объяснение и за указание на возможное решение. Вы правы, что это имеет смысл. Я проверял типы для всех различных методов, которые я использовал, но я был введен в заблуждение документами, говорящими «fn iter (& self) -> Iter ', поэтому я царапал себе голову. Теперь я знаю, где я должен был искать. – neverfox

+1

Я делаю много щелчков по типам в онлайн-документации! Вы изучаете всевозможные вещи. –

Смежные вопросы