Как вернуть структуру с типом данных модуля? - PullRequest
0 голосов
/ 24 августа 2018

Я пытаюсь реализовать пользовательский набор.Это может быть скомпилировано без проблем:

struct CustomSet {}

impl CustomSet {
    pub fn new() -> CustomSet {
        CustomSet {}
    }
}

Когда я попытался добавить тип модуля (пустой кортеж) в тип CustomSet, он не скомпилируется.

struct CustomSet<()> {}

impl CustomSet<()> {
    pub fn new() -> CustomSet<()> {
        CustomSet {}
    }
}

Ошибка со следующим

error: expected one of `>`, identifier, or lifetime, found `(`
 --> src/lib.rs:1:18
  |
1 | struct CustomSet<()> {}
  |                  ^ expected one of `>`, identifier, or lifetime here

Как вернуть структуру с типом данных модуля?Что я сделал не так?

Ответы [ 2 ]

0 голосов
/ 24 августа 2018

Тип CustomSet<()> имеет смысл, только если CustomSet определен параметром типа.Параметр типа - это переменная, а не другой тип, поэтому ваше определение не имеет смысла.Скорее, вам нужно определить его с помощью переменной:

struct CustomSet<T> {}

Это означает, что CustomSet определено для любого возможного типа T (с оговоркой, что тип должен быть Sized, чтоtrue для большинства типов).

Теперь приведенное выше определение не будет работать так, как оно есть, потому что Rust будет жаловаться, что вы не используете переменную T внутри типа.Какой смысл в переменной, которую вы не используете?

Как сказал hellow , вы можете использовать PhantomData, но это скорее обходной путь, когда вам нужна переменная, но нена самом деле не нужно использовать его по какой-то причине.Поскольку вы реализуете коллекцию, вам нужно будет использовать T для хранения значений где-либо:

struct CustomSet<T> {
    data: Vec<T>,
}

Поведение этого типа все еще может быть реализовано для все возможные T, а не просто (), что дает вам многократное повторное использование кода:

impl<T> CustomSet<T> {
    pub fn new() -> CustomSet<T> {
        CustomSet {
            data: Vec::new(),
        }
    }
}

Только тогда, когда вы фактически используете тип, который вам нужно ограничить T вообще:

let my_set: CustomSet<()> = CustomSet::new();

Даже эта аннотация типа часто не требуется в реальной программе, так как это может быть выведено из использования.Например, если вы предоставили метод insert для CustomSet, вы можете использовать его следующим образом:

// type annotation not needed because it will be inferred from the next line
let mut my_set = CustomSet::new();
my_set.insert(());
0 голосов
/ 24 августа 2018

В этом случае вы должны использовать PhantomData

use std::marker::PhantomData;

struct CustomSet<T> {
    _phantom: PhantomData<T>,
}

impl CustomSet<()> {
    pub fn new() -> CustomSet<()> {
        CustomSet {
            _phantom: PhantomData,
        }
    }
}

PhantomData "сообщает" компилятору, что используется аргумент T, и поэтому больше не будет жаловаться на это.

Обратите внимание, что хотя вы добавляете элемент в свою структуру, он больше не будет использовать размер.

fn main() {
    println!("{}", std::mem::size_of::<CustomSet<()>>());  // 0
    println!("{}", std::mem::size_of::<CustomSet<u32>>()); // 0
} 
...