Как мне создать Ve c<T>, где T: Into <_> в Rust? - PullRequest
0 голосов
/ 29 марта 2020

Это мой пример кода. Я пытаюсь передать Vec<T> в функцию, где T: Into<_>!

enum Test {
  FN(Box<dyn Fn()>),
  STR(String),
}

impl<F> From<F> for Test
  where F: Fn() + 'static
{
  fn from(f: F) -> Self {
    Self::FN(Box::new(f))
  }
}

impl From<String> for Test {
  fn from(s: String) -> Self {
    Self::STR(s)
  }
}

fn main() {
  into(vec![
    || println!("func 1"),
    || println!("func 2"),
    String::from("string 1"),
  ]);
}

fn into<T>(v: Vec<T>)
  where T: Into<Test>
{
  for test in v {
    let test = test.into();
    match test {
      Test::FN(func) => func(),
      Test::STR(s) => println!("{}", s),
    }
  }
}

Ошибка при втором закрытии:

expected closure, found a different closure

Проблема в том, что Into <_ > не может быть dyn, потому что он Sized, так что это не работает!

Я надеюсь на вывод:

func 1
func 2
string 1

Любые ответы или идеи?!

Ответы [ 4 ]

2 голосов
/ 30 марта 2020

Rust обычно не приводит к принудительному типу автоматически. Вы определили свои From реализации, но ничто их не вызывает. Вам нужно изменить свою функцию, чтобы она была более похожа на

fn main() {
  into(vec![
    Test::from(|| println!("func 1")),
    Test::from(|| println!("func 2")),
    Test::from(String::from("string 1")),
  ]);
}
1 голос
/ 30 марта 2020

То, что вы создаете перечисление Test, не означает, что Rust примирит тип вашего гетерогенного вектора, равный Test. Вы должны вручную создать экземпляр каждого варианта enum (и поставить Box вокруг ваших замыканий):

fn main() {
  let x: Vec<Test> = vec![
    Test::FN(Box::new(|| println!("func 1"))),
    Test::FN(Box::new(|| println!("func 2"))),
    Test::STR(String::from("string 1")),
  ];
  into(x);
}
0 голосов
/ 30 марта 2020

Спасибо за все ответы, я нашел свое собственное решение, создав собственную черту MyInto:


trait MyInto {
  fn my_into(&self) -> Test;
}

enum Test<'l> {
  FN(&'l dyn Fn()),
  STR(String),
}

impl<F> MyInto for F
  where F: Fn() + 'static
{
  fn my_into(&self) -> Test {
    Test::FN(self)
  }
}

impl MyInto for String {
  fn my_into(&self) -> Test {
    Test::STR(self.to_owned())
  }
}

fn main() {
  into(vec![
    &|| println!("func 1"),
    &|| println!("func 2"),
    &String::from("string 1"),
  ]);
}

fn into(v: Vec<&dyn MyInto>) {
  for test in v {
    let test = test.my_into();
    match test {
      Test::FN(func) => func(),
      Test::STR(s) => println!("{}", s),
    }
  }
}

Вывод теперь:

func 1
func 2
string 1

Сейчас можно использовать dyn в &dyn MyInto, потому что MyInto не Sized!

0 голосов
/ 30 марта 2020

Ваша идея состоит в том, чтобы иметь Vec объектов, которые можно конвертировать для тестирования. Однако для Vec требуются объекты одного типа:

  • каждое закрытие имеет свой тип
  • Строка отличается от типов закрытия

Пример с Vec с элементами одного типа может быть Vec только одного из ваших элементов:

  into(vec![|| println!("func 1")]); 
  into(vec![|| println!("func 2")]);
  into(vec![String::from("string 1")]);
  // each has one element of ONE type, this compiles and runs

или Vec нескольких элементов одного типа:

  into(vec![String::from("string 1"), String::from("string 2")]);
  // each has multiple element of ONE type (String), this compiles and runs

Чтобы ваш пример компилировался, вам нужно будет обернуть ваши элементы в тип обертки (например, enum), который реализует Into<Test>.

Ваш конкретный пример уже содержит такой тип обертки (* 1023) *) и, таким образом, ваш пример, к сожалению, становится тривиальным, потому что, если вы уже добавили Test s в свои Vec, вам больше не придется обращаться к ним (это показано в других примерах).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...