I have a trait with a couple of implementations, and I want to return the object so I can chain calls.
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());
}
I get errors:
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
The only thing that might work is to Box
self, like I do in the new()
functions, but I don't want to create any extra code by chaining... which is really just a convenience anyway.
Returning &mut Self
and using Box<impl RequestInfo>
almost works.... except that I have a function that returns either a LoggedIn
object or a LoggedOut
object, so here's revised code:
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());
}
And it gives the following error (earlier in the function it returned a LoggedIn
object):
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)