Rust泛型:列表中的每个元素都来自相同的特性?

huangapple go评论92阅读模式
英文:

Rust generics: list where each element is from the same trait?

问题

我在Rust用户论坛上找到了这个问题:Generics: Can I say "tuple where each element is FromSql"。基本上,问题是想知道如何做类似这样的事情:

  1. trait Foo {}
  2. struct A {}
  3. impl Foo for A {}
  4. struct B {}
  5. impl Foo for B {}
  6. fn main() {
  7. let x = (A{}, A{}, B{}, A{});
  8. bar(x);
  9. }
  10. fn bar<T: Foo>(tuple: (T...)) {
  11. }

这段代码不起作用,只是一个可能的样子。

那么,我们该如何做呢?

英文:

I found this question on the Rust users forum : Generics: Can I say "tuple where each element is FromSql". Basically, the questions was to know how do something like that :

  1. trait Foo {}
  2. struct A {}
  3. impl Foo for A {}
  4. struct B {}
  5. impl Foo for B {}
  6. fn main() {
  7. let x = (A{}, A{}, B{}, A{});
  8. bar(x);
  9. }
  10. fn bar&lt;T: Foo&gt;(tuple: (T...)) {
  11. }

> This code does not work, it's an idea of how it could look like.

So, how can we do that?

答案1

得分: 0

  • 创建一个名为ToAny的特性,将为我们的所有结构体实现它。
  1. use std::any::Any;
  2. pub trait ToAny {
  3. fn as_any(&self) -> &dyn Any;
  4. }
  • 让我们创建我们的特性
  1. trait Foo: ToAny {}

这需要实现ToAny特性,以强制每个实现Foo的结构体也实现ToAny

  • 让我们创建我们的结构体:
  1. struct A {
  2. id: i32,
  3. }
  4. impl ToAny for A {
  5. fn as_any(&self) -> &dyn Any {
  6. self
  7. }
  8. }
  9. impl Foo for A {}
  10. struct B {
  11. id: i32,
  12. }
  13. impl ToAny for B {
  14. fn as_any(&self) -> &dyn Any {
  15. self
  16. }
  17. }
  18. impl Foo for B {}

ToAny的实现始终相同,我们可以轻松创建一个宏来实现它。

  • 然后,我们可以创建一个Vec来存储我们的值,而不是使用元组:
  1. let boxeds: Vec<Box<dyn A>> = vec![
  2. Box::new(A {id: 1}),
  3. Box::new(B {id: 2}),
  4. Box::new(A {id: 3}),
  5. Box::new(B {id: 4}),
  6. ];
  7. // 存储是`B`的值。
  8. let mut bees: Vec<&B> = vec![];
  9. for boxed in &boxeds {
  10. // 如果`boxed`包含`B`值,则为`Some(x)`。
  11. let found = match boxed.as_any().downcast_ref::<B>() {
  12. Some(b) => b,
  13. None => {}, // 这是`A`值。
  14. };
  15. bees.push(found);
  16. }
  17. assert_eq!(bees, vec![
  18. &B {id: 2},
  19. &B {id: 4}
  20. ]);

如果我们参考问题,以下代码:

  1. fn bar<T: Foo>(tuple: (T...)) {
  2. }

可以成为有效的代码:

  1. fn bar(values: Vec<Box<dyn Foo>) {
  2. }

我在这个帖子中已更改了名称,FooA,并且只有 B 结构体。

英文:
  • The first step is to create a ToAny trait that will be implemented for all our structures.
  1. use std::any::Any;
  2. pub trait ToAny {
  3. fn as_any(&amp;self) -&gt; &amp;dyn Any;
  4. }
  • Let's create our trait
  1. trait Foo: ToAny {}

> It requires implementing the ToAny trait to force each structure implementing Foo to implement ToAny too.

  • Let's create our structures:
  1. struct A {
  2. id: i32,
  3. }
  4. impl ToAny for A {
  5. fn as_any(&amp;self) -&gt; &amp;dyn Any {
  6. self
  7. }
  8. }
  9. impl Foo for A {}
  10. struct B {
  11. id: i32,
  12. }
  13. impl ToAny for B {
  14. fn as_any(&amp;self) -&gt; &amp;dyn Any {
  15. self
  16. }
  17. }
  18. impl Foo for B {}

The implementation of ToAny is always the same, we could create a macro implementing it easily.

  • And then, we can create a Vec instead of a tuple to store our values:
  1. let boxeds: Vec&lt;Box&lt;dyn A&gt;&gt; = vec![
  2. Box::new(A {id: 1}),
  3. Box::new(B {id: 2}),
  4. Box::new(A {id: 3}),
  5. Box::new(B {id: 4}),
  6. ];
  7. // Stores the values being `B`.
  8. let mut bees: Vec&lt;&amp;B&gt; = vec![];
  9. for boxed in &amp;boxeds {
  10. // `Some(x)` if `boxed` contains a `B` value.
  11. let found = match boxed.as_any().downcast_ref::&lt;B&gt;() {
  12. Some(b) =&gt; b,
  13. None =&gt; {}, // it is a `A` value.
  14. };
  15. bees.push(found);
  16. }
  17. assert_eq!(bees, vec![
  18. &amp;B {id: 2},
  19. &amp;B {id: 4}
  20. ]);

If we refer to the question, the following code:

  1. fn bar&lt;T: Foo&gt;(tuple: (T...)) {
  2. }

can be this valid code:

  1. fn bar(values: Vec&lt;Box&lt;dyn Foo&gt;&gt;) {
  2. }

I've written a gist file being tests for that. Be careful, I've changed the names in this post, Foo is A and there is only the B structure.

答案2

得分: 0

  1. 使用宏来为元组实现 `Foo`
  2. ```rust
  3. trait Foo {
  4. fn do_it(&self);
  5. }
  6. struct A {}
  7. impl Foo for A {
  8. fn do_it(&self) {
  9. print!("A");
  10. }
  11. }
  12. struct B {}
  13. impl Foo for B {
  14. fn do_it(&self) {
  15. print!("B");
  16. }
  17. }
  18. fn main() {
  19. let x = (A{}, A{}, B{}, A{});
  20. bar(x);
  21. }
  22. fn bar<T: Foo>(tuple: T) {
  23. tuple.do_it();
  24. }
  25. macro_rules! impl_Foo_for_tuple {
  26. ( $first:ident $($rest:ident)* ) => {
  27. impl<$first: Foo, $( $rest : Foo, )* > Foo for ( $first, $($rest,)* ) {
  28. fn do_it(&self) {
  29. #[allow(non_snake_case)]
  30. let ( $first, $($rest,)* ) = self;
  31. $first.do_it();
  32. $( $rest.do_it(); )*
  33. }
  34. }
  35. impl_Foo_for_tuple!( $($rest)* );
  36. };
  37. () => {};
  38. }
  39. impl_Foo_for_tuple!(A B C D E F G H I J K L M);
  1. <details>
  2. <summary>英文:</summary>
  3. Use a macro to implement `Foo` for tuples:
  4. ```rust
  5. trait Foo {
  6. fn do_it(&amp;self);
  7. }
  8. struct A {}
  9. impl Foo for A {
  10. fn do_it(&amp;self) {
  11. print!(&quot;A&quot;);
  12. }
  13. }
  14. struct B {}
  15. impl Foo for B {
  16. fn do_it(&amp;self) {
  17. print!(&quot;B&quot;);
  18. }
  19. }
  20. fn main() {
  21. let x = (A{}, A{}, B{}, A{});
  22. bar(x);
  23. }
  24. fn bar&lt;T: Foo&gt;(tuple: T) {
  25. tuple.do_it();
  26. }
  27. macro_rules! impl_Foo_for_tuple {
  28. ( $first:ident $($rest:ident)* ) =&gt; {
  29. impl&lt; $first: Foo, $( $rest : Foo, )* &gt; Foo for ( $first, $($rest,)* ) {
  30. fn do_it(&amp;self) {
  31. #[allow(non_snake_case)]
  32. let ( $first, $($rest,)* ) = self;
  33. $first.do_it();
  34. $( $rest.do_it(); )*
  35. }
  36. }
  37. impl_Foo_for_tuple!( $($rest)* );
  38. };
  39. () =&gt; {};
  40. }
  41. impl_Foo_for_tuple!(A B C D E F G H I J K L M);

huangapple
  • 本文由 发表于 2023年2月18日 21:36:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75493701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定