Trait object as associated type of a trait object.

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

Trait object as associated type of a trait object

问题

I can provide the translated code part as requested:

我编写了两个实现共同特征 `Solve` 的结构体。`Solve` 具有与特质绑定 `Display` 的关联类型 `Answer`。我希望函数 `create_solver` 返回 `Solve` 的特质对象。

我需要帮助编写关联类型 `Answer = ??`。

```rust
use std::fmt::Display;

fn main() {
    let solver = create_solver(2);
    
    let answer = solver.solve();
    
    println!("{}", answer);
}

fn create_solver(kind: u32) -> Box<dyn Solve<Answer = ??>> {
    match kind {
        1 => Box::new(SolverOne),
        2 => Box::new(SolverTwo),
        _ => unreachable!()
    }
}

trait Solve {
    type Answer: Display;
    
    fn solve(&self) -> Self::Answer;
}

struct SolverOne;

impl Solve for SolverOne {
    type Answer = u32;

    fn solve(&self) -> Self::Answer {
        3
    }
}

struct SolverTwo;

impl Solve for SolverTwo {
    type Answer = String;
    
    fn solve(&self) -> Self::Answer {
        String::from("three")
    }
}

我尝试设置 Answer = Box<dyn Display>,但导致错误。

fn create_solver(kind: u32) -> Box<dyn Solve<Answer = Box<dyn Display>>> {
    match kind {
        1 => Box::new(SolverOne),
        2 => Box::new(SolverTwo),
        _ => unreachable!()
    }
}

trait Solve {
    type Answer: Display;
    
    fn solve(&self) -> Self::Answer;
}

struct SolverOne;

impl Solve for SolverOne {
    type Answer = Box<u32>;

    fn solve(&self) -> Self::Answer {
        Box::new(3)
    }
}

struct SolverTwo;

impl Solve for SolverTwo {
    type Answer = Box<String>;
    
    fn solve(&self) -> Self::Answer {
        Box::new(String::from("three"))
    }
}

错误消息:

error[E0271]: 类型不匹配,解析为 `<SolverOne as Solve>::Answer == Box<(dyn Display + 'static)>`
  --> src/main.rs:13:14
   |
13 |         1 => Box::new(SolverOne),
   |              ^^^^^^^^^^^^^^^^^^^ 类型不匹配,解析为 `<SolverOne as Solve>::Answer == Box<(dyn Display + 'static)>`
   |
注意: 预期为 `Box<(dyn std::fmt::Display + 'static)>`
  --> src/main.rs:28:19
   |
28 |     type Answer = Box<u32>;
   |                   ^^^^^^^^
   = 注意: 预期的结构是 `Box<(dyn std::fmt::Display + 'static)>`
              找到的结构是 `Box<u32>`
   = 注意: 需要将 `SolverOne` 转换为对象类型 `dyn Solve<Answer = Box<(dyn std::fmt::Display + 'static)>>`

error[E0271]: 类型不匹配,解析为 `<SolverTwo as Solve>::Answer == Box<(dyn Display + 'static)>`
  --> src/main.rs:12:5
   |
12 | /     match kind {
13 | |         1 => Box::new(SolverOne),
14 | |         2 => Box::new(SolverTwo),
15 | |         _ => unreachable!()
16 | |     }
   | |_____^ 类型不匹配,解析为 `<SolverTwo as Solve>::Answer == Box<(dyn Display + 'static)>`
   |
注意: 预期为 `Box<(dyn std::fmt::Display + 'static)>`
  --> src/main.rs:38:19
   |
38 |     type Answer = Box<String>;
   |                   ^^^^^^^^^^^
   = 注意: 预期的结构是 `Box<(dyn std::fmt::Display + 'static)>`
              找到的结构是 `Box<String>`
   = 注意: 需要将 `SolverTwo` 转换为对象类型 `dyn Solve<Answer = Box<(dyn std::fmt::Display + 'static)>>`

有关此错误的更多信息,请尝试 `rustc --explain E0271`

您应该将 Answer = 设置为什么,以使其正常工作?


请注意,您要求翻译的代码片段可能包含代码错误或不完整的信息。因此,我无法为您提供完整的解决方案,但您需要将 `Answer` 设置为与实际返回类型匹配的类型,这可以是 `u32` 或 `String`,而不是 `Box<dyn Display>`。如果有其他问题,请提供更多详细信息,以便我可以提供更具体的帮助。
<details>
<summary>英文:</summary>
I wrote two structs that implement a common trait `Solve`. `Solve` has an associated type `Answer` with trait bound `Display`. I want the function `create_solver` to return a trait object of `Solve`.
I need help with writing the associate type `Answer = ??`.

use std::fmt::Display;

fn main() {
let solver = create_solver(2);

let answer = solver.solve();
println!(&quot;{}&quot;, answer);

}

fn create_solver(kind: u32) -> Box<dyn Solve<Answer = ??>> {
match kind {
1 => Box::new(SolverOne),
2 => Box::new(SolverTwo),
_ => unreachable!()
}
}

trait Solve {
type Answer: Display;

fn solve(&amp;self) -&gt; Self::Answer;

}

struct SolverOne;

impl Solve for SolverOne {
type Answer = u32;

fn solve(&amp;self) -&gt; Self::Answer {
3
}

}

struct SolverTwo;

impl Solve for SolverTwo {
type Answer = String;

fn solve(&amp;self) -&gt; Self::Answer {
String::from(&quot;three&quot;)
}

}


I tried setting `Answer = Box&lt;dyn Display&gt;` but that results in error.

fn create_solver(kind: u32) -> Box<dyn Solve<Answer = Box<dyn Display>>> {
match kind {
1 => Box::new(SolverOne),
2 => Box::new(SolverTwo),
_ => unreachable!()
}
}

trait Solve {
type Answer: Display;

fn solve(&amp;self) -&gt; Self::Answer;

}

struct SolverOne;

impl Solve for SolverOne {
type Answer = Box<u32>;

fn solve(&amp;self) -&gt; Self::Answer {
Box::new(3)
}

}

struct SolverTwo;

impl Solve for SolverTwo {
type Answer = Box<String>;

fn solve(&amp;self) -&gt; Self::Answer {
Box::new(String::from(&quot;three&quot;))
}

}


Error message:

error[E0271]: type mismatch resolving &lt;SolverOne as Solve&gt;::Answer == Box&lt;(dyn Display + &#39;static)&gt;
--> src/main.rs:13:14
|
13 | 1 => Box::new(SolverOne),
| ^^^^^^^^^^^^^^^^^^^ type mismatch resolving &lt;SolverOne as Solve&gt;::Answer == Box&lt;(dyn Display + &#39;static)&gt;
|
note: expected this to be Box&lt;(dyn std::fmt::Display + &#39;static)&gt;
--> src/main.rs:28:19
|
28 | type Answer = Box<u32>;
| ^^^^^^^^
= note: expected struct Box&lt;(dyn std::fmt::Display + &#39;static)&gt;
found struct Box&lt;u32&gt;
= note: required for the cast from SolverOne to the object type dyn Solve&lt;Answer = Box&lt;(dyn std::fmt::Display + &#39;static)&gt;&gt;

error[E0271]: type mismatch resolving &lt;SolverTwo as Solve&gt;::Answer == Box&lt;(dyn Display + &#39;static)&gt;
--> src/main.rs:12:5
|
12 | / match kind {
13 | | 1 => Box::new(SolverOne),
14 | | 2 => Box::new(SolverTwo),
15 | | _ => unreachable!()
16 | | }
| |_____^ type mismatch resolving &lt;SolverTwo as Solve&gt;::Answer == Box&lt;(dyn Display + &#39;static)&gt;
|
note: expected this to be Box&lt;(dyn std::fmt::Display + &#39;static)&gt;
--> src/main.rs:38:19
|
38 | type Answer = Box<String>;
| ^^^^^^^^^^^
= note: expected struct Box&lt;(dyn std::fmt::Display + &#39;static)&gt;
found struct Box&lt;String&gt;
= note: required for the cast from SolverTwo to the object type dyn Solve&lt;Answer = Box&lt;(dyn std::fmt::Display + &#39;static)&gt;&gt;

For more information about this error, try rustc --explain E0271


What should I set as `Answer = ` to make this work?
</details>
# 答案1
**得分**: 2
以下是要翻译的内容:
关联类型必须对所有返回的类型相同,而您没有这样的关联类型。但您可以创建一个使用类型擦除返回 `Box<dyn Display>` 的包装类型:
```rust
fn create_solver(kind: u32) -> Box<dyn Solve<Answer = Box<dyn Display>> {
struct ErasedSolver<T>(T);
impl<T: Solve> Solve for ErasedSolver<T>
where
T::Answer: 'static,
{
type Answer = Box<dyn Display>;
fn solve(&self) -> Self::Answer {
Box::new(self.0.solve())
}
}
match kind {
1 => Box::new(ErasedSolver(SolverOne)),
2 => Box::new(ErasedSolver(SolverTwo)),
_ => unreachable!(),
}
}
英文:

The associated type has to be the same for all types returned, and you have no such associated type. But you can create a wrapper type that using type erasure returns Box&lt;dyn Display&gt;:

fn create_solver(kind: u32) -&gt; Box&lt;dyn Solve&lt;Answer = Box&lt;dyn Display&gt;&gt;&gt; {
    struct ErasedSolver&lt;T&gt;(T);
    impl&lt;T: Solve&gt; Solve for ErasedSolver&lt;T&gt;
    where
        T::Answer: &#39;static,
    {
        type Answer = Box&lt;dyn Display&gt;;

        fn solve(&amp;self) -&gt; Self::Answer {
            Box::new(self.0.solve())
        }
    }

    match kind {
        1 =&gt; Box::new(ErasedSolver(SolverOne)),
        2 =&gt; Box::new(ErasedSolver(SolverTwo)),
        _ =&gt; unreachable!(),
    }
}

答案2

得分: 0

以下是代码部分的翻译:

这几乎是与[使Clone对象安全][1]相同的问题,为此有[`dyn-clone`][2]。您可以通过创建另一个trait和一个全局impl来在这里执行相同的操作

trait SolveBoxed {
    fn solve_boxed(&self) -> Box<dyn Display>;
}

impl<T, D> SolveBoxed for T
where
    T: Solve<Answer = D>,
    D: Display + 'static,
{
    fn solve_boxed(&self) -> Box<dyn Display> {
        Box::new(self.solve())
    }
}

完整代码:(playground)

use std::fmt::Display;

fn main() {
    let solver = create_solver(2);

    let answer = solver.solve_boxed();

    println!("{}", answer);
}

fn create_solver(kind: u32) -> Box<dyn SolveBoxed> {
    match kind {
        1 => Box::new(SolverOne),
        2 => Box::new(SolverTwo),
        _ => unreachable!(),
    }
}

trait SolveBoxed {
    fn solve_boxed(&self) -> Box<dyn Display>;
}

impl<T, D> SolveBoxed for T
where
    T: Solve<Answer = D>,
    D: Display + 'static,
{
    fn solve_boxed(&self) -> Box<dyn Display> {
        Box::new(self.solve())
    }
}

trait Solve {
    type Answer: Display;

    fn solve(&self) -> Self::Answer;
}

struct SolverOne;

impl Solve for SolverOne {
    type Answer = u32;

    fn solve(&self) -> Self::Answer {
        3
    }
}

struct SolverTwo;

impl Solve for SolverTwo {
    type Answer = String;

    fn solve(&self) -> Self::Answer {
        String::from("three")
    }
}

<details>
<summary>英文:</summary>
This is almost the same problem as [making Clone object-safe][1], for which there&#39;s [`dyn-clone`][2]. You can do the same thing here by making another trait and a blanket impl:
```rs
trait SolveBoxed {
fn solve_boxed(&amp;self) -&gt; Box&lt;dyn Display&gt;;
}
impl&lt;T, D&gt; SolveBoxed for T
where
T: Solve&lt;Answer = D&gt;,
D: Display + &#39;static,
{
fn solve_boxed(&amp;self) -&gt; Box&lt;dyn Display&gt; {
Box::new(self.solve())
}
}

Full code: (playground)

use std::fmt::Display;

fn main() {
    let solver = create_solver(2);

    let answer = solver.solve_boxed();

    println!(&quot;{}&quot;, answer);
}

fn create_solver(kind: u32) -&gt; Box&lt;dyn SolveBoxed&gt; {
    match kind {
        1 =&gt; Box::new(SolverOne),
        2 =&gt; Box::new(SolverTwo),
        _ =&gt; unreachable!(),
    }
}

trait SolveBoxed {
    fn solve_boxed(&amp;self) -&gt; Box&lt;dyn Display&gt;;
}

impl&lt;T, D&gt; SolveBoxed for T
where
    T: Solve&lt;Answer = D&gt;,
    D: Display + &#39;static,
{
    fn solve_boxed(&amp;self) -&gt; Box&lt;dyn Display&gt; {
        Box::new(self.solve())
    }
}

trait Solve {
    type Answer: Display;

    fn solve(&amp;self) -&gt; Self::Answer;
}

struct SolverOne;

impl Solve for SolverOne {
    type Answer = u32;

    fn solve(&amp;self) -&gt; Self::Answer {
        3
    }
}

struct SolverTwo;

impl Solve for SolverTwo {
    type Answer = String;

    fn solve(&amp;self) -&gt; Self::Answer {
        String::from(&quot;three&quot;)
    }
}

huangapple
  • 本文由 发表于 2023年3月21日 02:07:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75793849.html
匿名

发表评论

匿名网友

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

确定