使用不同的实现返回性状实现

发布于 2025-02-09 13:12:16 字数 1106 浏览 0 评论 0 原文

以下实现似乎很简单。由于某种原因,我不明白问题是什么。编译器不编译。

这里的主要问题是我无法更改函数 test(bool)的声明,因为它不在框架之外。

/// Implemented in a 3rd party framework:
trait Share {
    fn dosomething();
}

impl Share for String {
    fn dosomething() {
        todo!()
    }
}

/// My part of the implementation:
// this function `test` will be handed over (as a function) to a framework method, which I can't change it's return type.

fn test(data: bool) -> Result<impl Share, String> {
    return if data {
        Ok(Data {})
    } else {
        Ok("a string".to_string())
    }
}



struct Data {

}

impl Share for Data {
    fn dosomething() {
        todo!()
    }
}
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/lib.rs:5:12
  |
5 |         Ok("a string".to_string())
  |            ^^^^^^^^^^^^^^^^^^^^^^ expected struct `Data`, found struct `String`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

The following implementation seems quite simple. for some reason I don't get what the problem is. Compiler doesn't compile.

The main problem here is that I cannot change the declaration of the function test(bool) since it's out of a framework.

/// Implemented in a 3rd party framework:
trait Share {
    fn dosomething();
}

impl Share for String {
    fn dosomething() {
        todo!()
    }
}

/// My part of the implementation:
// this function `test` will be handed over (as a function) to a framework method, which I can't change it's return type.

fn test(data: bool) -> Result<impl Share, String> {
    return if data {
        Ok(Data {})
    } else {
        Ok("a string".to_string())
    }
}



struct Data {

}

impl Share for Data {
    fn dosomething() {
        todo!()
    }
}
   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/lib.rs:5:12
  |
5 |         Ok("a string".to_string())
  |            ^^^^^^^^^^^^^^^^^^^^^^ expected struct `Data`, found struct `String`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山人契 2025-02-16 13:12:16

问题在于的两个分支如果 - else 表达式必须评估相同类型的值。但是,在您的代码中:

fn test(data: bool) -> Result<impl Share, String> {
    return if data {
        Ok(Data {}) // : Result<Data, String>
    } else {
        Ok("a string".to_string()) // : Result<String, String>
    }
}

第一个分支评估 ok(data {}),因此将其类型推断为 result&lt; data,string&gt; ,而第二个分支评估为 ok(“ a String” .to_string()),并将其推断为 result&lt; string,string&gt; 。由于这些类型是不同的,因此会导致编译时间误差。


如果共享,例如:

trait Share {
    fn dosomething(&self);
}

然后,由于值 data {} “ a String” .TO_STRING()实现 share ,您通过将它们放在 box&lt; dyn共享&gt; 中,可以将它们变成特征对象。这样,您仍然可以通过依靠动态多态性来实现(运行时间 x )类型擦除:

fn test(data: bool) -> Result<Box<dyn Share>, String> {
    return if data {
        Ok(Box::new(Data{}))
    } else {
        Ok(Box::new("a string".to_string()))
    }
}

请注意,此处两个分支值都是相同类型的: result&lt; box&lt; dyn&lt; dyn&lt; dyn&gt&gt ;,字符串&gt; 因为类型 box&lt; share&gt; and box&lt; string&gt; 在运行时删除 > box&lt; dyn共享&gt; 。


x 您的目标是使用您的初始 Impl share 瞄准编译时类型的擦除。

The problem is that both branches of the if-else expression must evaluate to a value of the same type. However, in your code:

fn test(data: bool) -> Result<impl Share, String> {
    return if data {
        Ok(Data {}) // : Result<Data, String>
    } else {
        Ok("a string".to_string()) // : Result<String, String>
    }
}

The first branch evaluates to Ok(Data {}), and therefore its type would be inferred as Result<Data, String>, whereas the second branch evaluates to Ok("a string".to_string()) and it would be inferred as Result<String, String>. Since these types are different, it results in a compile-time error.


If Share were an object-safe trait, e.g.:

trait Share {
    fn dosomething(&self);
}

Then, since the values Data{} and "a string".to_string() implement Share, you could turn them into trait objects by placing them into a Box<dyn Share>. This way, you would still achieve a (run-timeX) type erasure by relying on dynamic polymorphism:

fn test(data: bool) -> Result<Box<dyn Share>, String> {
    return if data {
        Ok(Box::new(Data{}))
    } else {
        Ok(Box::new("a string".to_string()))
    }
}

Note that here both branch values are of the same type: Result<Box<dyn Share>, String> because the types Box<Share> and Box<String> are erased at run-time to Box<dyn Share>.


XYou were aiming at a compile-time type erasure with your initial impl Share.

何以心动 2025-02-16 13:12:16

如果您确实需要为结果的 OK 变体提供不同的类型,则所有这些类型都实现 share ,则必须切换到动态多态性。

fn test(data: bool) -> Result<Box<dyn Share>, String> {
    if data {
        Ok(Box::new(Data {}))
    } else {
        Ok(Box::new("a string".to_string()))
    }
}

trait Share {
    fn dosomething(&self);
}

impl Share for String {
    fn dosomething(&self) {
        println!("something on String");
    }
}

struct Data {}

impl Share for Data {
    fn dosomething(&self) {
        println!("something on Data");
    }
}

fn main() {
    if let Ok(s) = test(true) {
        s.dosomething();
    }
    if let Ok(s) = test(false) {
        s.dosomething();
    }
}

这意味着堆分配( box ),因为该值是在函数内部产生的(您无法返回对本地的引用)。

但是,如果您只想提供实施共享的有限类型,则可以返回 enum 而不是 Impl Inld share

enum VariousTypes {
    D(Data),
    S(String),
}

impl Share for VariousTypes {
    fn dosomething(&self) {
        match self {
            Self::D(d) => d.dosomething(),
            Self::S(s) => s.dosomething(),
        }
    }
}

fn test(data: bool) -> Result<VariousTypes, String> {
    if data {
        Ok(VariousTypes::D(Data {}))
    } else {
        Ok(VariousTypes::S("a string".to_string()))
    }
}

trait Share {
    fn dosomething(&self);
}

impl Share for String {
    fn dosomething(&self) {
        println!("something on String");
    }
}

struct Data {}

impl Share for Data {
    fn dosomething(&self) {
        println!("something on Data");
    }
}

fn main() {
    if let Ok(s) = test(true) {
        s.dosomething();
    }
    if let Ok(s) = test(false) {
        s.dosomething();
    }
}

If you really need to provide different types for the Ok variant of the result, all of them implementing Share, then you have to switch to dynamic polymorphism.

fn test(data: bool) -> Result<Box<dyn Share>, String> {
    if data {
        Ok(Box::new(Data {}))
    } else {
        Ok(Box::new("a string".to_string()))
    }
}

trait Share {
    fn dosomething(&self);
}

impl Share for String {
    fn dosomething(&self) {
        println!("something on String");
    }
}

struct Data {}

impl Share for Data {
    fn dosomething(&self) {
        println!("something on Data");
    }
}

fn main() {
    if let Ok(s) = test(true) {
        s.dosomething();
    }
    if let Ok(s) = test(false) {
        s.dosomething();
    }
}

This implies heap allocation (Box) because the value is produced inside the function (you cannot return a reference to a local).

However, if you only want to provide a limited set of types implementing Share then, you can return an enum instead of impl Share.

enum VariousTypes {
    D(Data),
    S(String),
}

impl Share for VariousTypes {
    fn dosomething(&self) {
        match self {
            Self::D(d) => d.dosomething(),
            Self::S(s) => s.dosomething(),
        }
    }
}

fn test(data: bool) -> Result<VariousTypes, String> {
    if data {
        Ok(VariousTypes::D(Data {}))
    } else {
        Ok(VariousTypes::S("a string".to_string()))
    }
}

trait Share {
    fn dosomething(&self);
}

impl Share for String {
    fn dosomething(&self) {
        println!("something on String");
    }
}

struct Data {}

impl Share for Data {
    fn dosomething(&self) {
        println!("something on Data");
    }
}

fn main() {
    if let Ok(s) = test(true) {
        s.dosomething();
    }
    if let Ok(s) = test(false) {
        s.dosomething();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文