Заимствовать структуру с полем Строка в структуру с полем & amp; str? [Дубликат]

У меня была та же проблема. Это простая проблема, заключающаяся в том, что вы не указали правильный путь.

Щелкните правой кнопкой мыши по файлу .fxml и выберите свойства (для тех, кто использует eclipse, не будет сильно отличаться для другой IDE), а затем скопируйте скопируйте местоположение, начиная с /packagename до конца, и это должно решить проблему

12
задан Shepmaster 1 June 2018 в 01:46
поделиться

2 ответа

Похоже, вы этого хотите.

Cow будет принимать &str или String.

use std::borrow::Cow;

#[derive(Debug, Eq, Hash, PartialEq)]
struct Complex<'a> {
    n: i32,
    s: Cow<'a, str>,
}

impl<'a> Complex<'a> {
    fn new<S: Into<Cow<'a, str>>>(n: i32, s: S) -> Self {
        Complex {
            n: n,
            s: s.into(),
        }
    }
}

fn main() { 
    let mut m = std::collections::HashMap::<Complex, i32>::new();
    m.insert(Complex::new(42, "foo"), 123);

    assert_eq!(123, *m.get(&Complex::new(42, "foo")).unwrap()); 
}

Комментарий о параметрах жизни:

Если вам не нравится параметр lifetime, и вам нужно работать только с &'static str или String, тогда вы можете использовать Cow<'static, str> и удалить другие параметры времени жизни из блока impl и определения структуры.

6
ответ дан A.B. 15 August 2018 в 19:21
поделиться
  • 1
    Мне понадобится день или два, чтобы переварить это. Это просто, но это у меня в голове. Моя основная проблема заключается в том, что в моем конкретном случае Complex отображается в API моего контейнера, поэтому мне нужно убедиться, что я могу обременять тип с помощью параметра продолжительности жизни, не слишком мутируя мой интерфейс. Моя первоначальная реакция заключается в том, что функциональность Cow для копирования на запись слишком тяжелая, потому что я никогда не делаю никакого копирования, но в некотором смысле я почти это, потому что иногда я использую экземпляры, а иногда я использую ссылки , После того как я закончу переваривать ваш ответ, я дам вам знать, как это работает. – Craig M. Brandenburg 8 April 2016 в 00:02
  • 2
    Вы могли бы избавиться от параметров времени жизни. См. Мое редактирование. – A.B. 8 April 2016 в 06:42
  • 3
    Я не могу исключить параметр lifetime, потому что иногда берусь из нестатического str. Тем не менее, мне очень нравится ваша идея, потому что это упростит код в другом месте, потому что новый Complex охватывает как случаи владения, так и заимствования - нет необходимости в уникальном типе для каждого случая. Одна вещь, которая меня интригует, заключается в том, что стандартная библиотека Rust не использовала путь использования Cow вместо двух типов, чтобы покрывать случаи владения и заимствования для Path / PathBuf et al. Идея Cow кажется более обобщенной, потому что она работает и для сложных типов. Это было сделано для эффективности во время выполнения? – Craig M. Brandenburg 8 April 2016 в 19:29

Вы можете следовать идеям, описанным в . Как реализовать HashMap с двумя ключами? . Вот ответ «заимствованный объект-объект», ответ на ваш случай:

Создайте признак, который мы можем использовать в качестве общей цели Borrow:

trait Key {
    fn to_key(&self) -> (i32, &str);
}

Реализовать HashMap -приобретенные черты для объекта-объекта:

use std::hash::{Hash, Hasher};

impl<'a> Hash for Key + 'a {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.to_key().hash(state)
    }
}

impl<'a> PartialEq for Key + 'a {
    fn eq(&self, other: &Self) -> bool {
        self.to_key() == other.to_key()
    }
}

impl<'a> Eq for Key + 'a {}

Реализовать признак для нашего основного типа и любых типов вторичного поиска:

impl Key for Complex {
    fn to_key(&self) -> (i32, &str) {
        (self.n, &self.s)
    }
}

impl<'a> Key for (i32, &'a str) {
    fn to_key(&self) -> (i32, &str) {
        (self.0, self.1)
    }
}

Реализовать Borrow для всех типов поиска, возвращающих наш объект-объект:

use std::borrow::Borrow;

impl<'a> Borrow<Key + 'a> for Complex {
    fn borrow(&self) -> &(Key + 'a) {
        self
    }
}

impl<'a> Borrow<Key + 'a> for (i32, &'a str) {
    fn borrow(&self) -> &(Key + 'a) {
        self
    }
}

Преобразовать объект-объект во время запроса:

assert_eq!(Some(&123), m.get((42, "foo").borrow() as &Key));

Полный код в playground


Важным «полученным» является то, что весь ваш первичный ключ и ваши вторичные ключи должны иметь хэш таким же образом. Это означает, что одни и те же значения должны идти в вычисление хэша в том же порядке и количестве.

Вы можете определить Hash вручную, чтобы убедиться, что ваш основной и дополнительный ключи hash одинаковы!

Вот еще один пример, на этот раз с перечислением:

#[derive(Debug, PartialEq, Eq)]
enum ConfigKey {
    Text(String),
    Binary(Vec<u8>),
}

Мы создаем параллельное перечисление, состоящее только из ссылок, поэтому его легко создать. Важно, чтобы мы определяли одни и те же варианты и в том же порядке, что и первичное перечисление, чтобы они были хэшированы одинаково. Мы полагаемся на то, что хеш String и &str использует тот же алгоритм, что и Vec<T> и &[T]:

impl ConfigKey {
    fn as_ref(&self) -> ConfigKeyRef {
        match self {
            ConfigKey::Text(t) => ConfigKeyRef::Text(t),
            ConfigKey::Binary(b) => ConfigKeyRef::Binary(b),
        }
    }
}

#[derive(Hash, PartialEq, Eq)]
enum ConfigKeyRef<'a> {
    Text(&'a str),
    Binary(&'a [u8]),
}

Мы используем это новое перечисление как наш общий базовый тип ключа :

trait Key {
    fn to_key(&self) -> ConfigKeyRef;
}

И реализуем нашу черту для наших первичных и вторичных ключей:

impl Key for ConfigKey {
    fn to_key(&self) -> ConfigKeyRef {
        self.as_ref()
    }
}

impl<'a> Key for &'a str {
    fn to_key(&self) -> ConfigKeyRef {
        ConfigKeyRef::Text(self)
    }
}

Полный код на игровой площадке

1
ответ дан Shepmaster 15 August 2018 в 19:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: