rust - 我如何从实现中返回特征以便我可以链式调用?

标签 rust traits

我有几个实现的特征,我想返回对象以便我可以链式调用。

pub trait RequestInfo {
    fn logged_in(&self) -> bool;
    fn put(&mut self, string: String) -> RequestInfo {
        self
    }
}

struct LoggedOut {}
impl LoggedOut {
    fn new() -> Box<RequestInfo> {
        Box::new(LoggedOut {})
    }
}
impl RequestInfo for LoggedOut {
    fn logged_in(&self) -> bool {
        false
    }
}

struct LoggedIn {
    output: Vec<String>,
}
impl LoggedIn {
    fn new() -> Box<RequestInfo> {
        Box::new(LoggedIn { output: Vec::new() })
    }
}
impl RequestInfo for LoggedIn {
    fn logged_in(&self) -> bool {
        true
    }
    fn put(&mut self, string: String) -> impl RequestInfo {
        self.output.push(string);
        self
    }
}

fn main() {
    let mut info = LoggedIn::new();
    info.put("abc".to_string()).put("def".to_string());
}

我收到错误:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:32:42
   |
32 |     fn put(&mut self, string: String) -> impl RequestInfo {
   |                                          ^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
 --> src/main.rs:4:9
  |
3 |     fn put(&mut self, string: String) -> RequestInfo {
  |                                          ----------- expected `(dyn RequestInfo + 'static)` because of return type
4 |         self
  |         ^^^^ expected trait RequestInfo, found &mut Self
  |
  = note: expected type `(dyn RequestInfo + 'static)`
             found type `&mut Self`

error[E0277]: the size for values of type `(dyn RequestInfo + 'static)` cannot be known at compilation time
 --> src/main.rs:3:42
  |
3 |     fn put(&mut self, string: String) -> RequestInfo {
  |                                          ^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `(dyn RequestInfo + 'static)`
  = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
  = note: the return type of a function must have a statically known size

唯一可能起作用的是 Box self ,就像我在 new() 中做的一样功能,但我不想通过链接创建任何额外的代码...无论如何这实际上只是一种方便。

返回 &mut Self并使用 Box<impl RequestInfo>几乎可以工作....除了我有一个返回 LoggedIn 的函数对象或 LoggedOut对象,所以这里是修改后的代码:

pub trait RequestInfo {
    fn logged_in(&self) -> bool;
    fn put(&mut self, string: String) -> &mut Self {
        self
    }
}

struct LoggedOut {}
impl LoggedOut {
    fn new() -> Box<impl RequestInfo> {
        Box::new(LoggedOut {})
    }
}
impl RequestInfo for LoggedOut {
    fn logged_in(&self) -> bool {
        false
    }
}

struct LoggedIn {
    output: Vec<String>,
}
impl LoggedIn {
    fn new() -> Box<impl RequestInfo> {
        Box::new(LoggedIn { output: Vec::new() })
    }
}
impl RequestInfo for LoggedIn {
    fn logged_in(&self) -> bool {
        true
    }
    fn put(&mut self, string: String) -> &mut Self {
        self.output.push(string);
        self
    }
}

fn get(flag: bool) -> Box<impl RequestInfo> {
    if flag {
        return LoggedIn::new();
    }
    LoggedOut::new()
}

fn main() {
    let mut info = get(true);
    info.put("abc".to_string()).put("def".to_string());
}

它给出了以下错误(在函数的前面它返回了一个 LoggedIn 对象):

error[E0308]: mismatched types
  --> src/main.rs:42:5
   |
42 |     LoggedOut::new()
   |     ^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
   |
   = note: expected type `std::boxed::Box<impl RequestInfo>` (opaque type)
              found type `std::boxed::Box<impl RequestInfo>` (opaque type)

最佳答案

我对此进行了更多思考,您可以无视我之前的回答。该解决方案不必要地复杂。我有办法专注于从 put 返回 &mut Self,即使根本没有要求这样做。您只需从 put 方法返回 &mut RequestInfo 就可以了。您付出的唯一代价是您不能再为 put 提供默认实现。

pub trait RequestInfo {
    fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo;
}

struct LoggedOut {}
impl RequestInfo for LoggedOut {
    fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
        self
    }
}

struct LoggedIn {
    output: Vec<String>,
}
impl LoggedIn {
    fn new() -> LoggedIn {
        LoggedIn { output: Vec::new() }
    }
}
impl RequestInfo for LoggedIn {
     fn put(self: &mut Self, string: String) -> &mut dyn RequestInfo {
        self.output.push(string);
        self
    }
}

fn get(flag: bool) -> Box<dyn RequestInfo> {
    if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}


fn main() {
    let mut info = get(false);
    info.put("abc".to_string()).put("def".to_string());
}

关于rust - 我如何从实现中返回特征以便我可以链式调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54239972/

相关文章:

rust - slice_mut 为 &mut [T]

rust - 如何将异步函数放入 Rust 中的映射中?

vector - 返回带有任意变量的错误枚举

macros - 在宏中构建枚举

rust - VecDeque和Vec是否都具有特征?

scala - 在Scala中扩展部分实现的局部函数

scala - 将特征视为另一个类的子类

Scala,扩展具有通用特征的对象

scala - 强制 Scala 特征不兼容

string - 如何构造具有多个具有不同生命周期的str变量的结构?