Im a bit confused by self. Could you please help me along?? Im trying to append or push a new value into the vec. This only shows me that I have no idea what self actually is. The error I'm getting is :
---- ^^^^ this call modifies `self` in-place
| |
| you probably want to use this value after calling the method...
= note: ...instead of the `()` output of method `push`
Why does the following work but...
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
fn append_bar(self) -> Self{
self.to_string() + "Bar"
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
this and...
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
this do not?
trait AppendBar<T> {
fn append_bar(self) -> Self;
}
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let mut bar = vec![String::from("Bar")];
bar.push(self);
bar
}
}
Because self is a Vec<String> and you can't push a Vec<String> into a Vec<String> (which the error message tells you: "Expected String got Vec<String>").
impl AppendBar for Vec<String> {
fn append_bar(self) -> Self{
let bar_vec = vec!["Bar".to_string()];
self.append(bar_vec)
}
}
Because Vec::append doesn't return anything, so you need to return self yourself (or take &mut self as parameter and return nothing).
impl<T> AppendBar<T> for Vec<T> {
fn append_bar(self) -> Self{
self.push("Bar".to_string())
}
}
Because "Bar".to_string() is not guaranteed to be a T for all types T.
Related
Rustaceans. when I start to write a BloomFilter example in rust. I found I have serveral problems have to solve. I struggle to solve them but no progress in a day. I need help, any suggestion will help me a lot, Thanks.
Problems
How to solve lifetime when pass a Iterator into another function?
// let bits = self.hash(value); // how to solve such lifetime error without use 'static storage?
// Below is a workaround code but need to computed in advanced.
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
How to solve cyclic-dependency between struts without modify lower layer code, e.g: bloom_filter ?
// cyclic-dependency:
// RedisCache -> BloomFilter -> Storage
// | ^
// ------------<impl>------------
//
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
Since rust does not have null value, How can I solve the cyclic-dependency initialization without any stubs?
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// I found can use Weak::new() to solve it,but need to downgrade a Rc reference.
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
Code
#![allow(unused)]
mod bloom_filter {
use std::{hash::Hash, marker::PhantomData};
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
// let bits = self.hash(value); // how to solve such lifetime error?
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.set(bits);
}
pub fn contains(&self, value: T) -> bool {
// lifetime problem same as Self::add(T)
let bits = Box::new(self.hash(value).collect::<Vec<u64>>().into_iter());
self.0.contains_all(bits)
}
fn hash<'a, H: Hash + 'a>(&self, _value: H) -> Box<dyn Iterator<Item = u64> + 'a> {
todo!()
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands, RedisResult};
use std::{
cell::RefCell,
rc::{Rc, Weak},
};
pub struct RedisCache<'a>(Client, RefCell<BloomFilter<&'a str>>);
impl<'a> RedisCache<'a> {
pub fn new() -> RedisCache<'a> {
let mut cache = RedisCache(
Client::open("redis://localhost").unwrap(),
// v-- need a BloomFilter stub to create RedisCache
RefCell::new(BloomFilter::new()),
);
// v--- cache ownership has moved here
let filter = BloomFilter::by(Box::new(cache));
cache.1.replace(filter);
return cache;
}
pub fn get(&mut self, key: &str, load_value: fn() -> Option<String>) -> Option<String> {
let filter = self.1.borrow();
if filter.contains(key) {
if let Ok(value) = self.0.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = self.0.set(key, &actual_value).unwrap();
return Some(actual_value);
}
}
return None;
}
}
impl<'a> Storage for RedisCache<'a> {
fn set(&mut self, bits: BitsIter) {
todo!()
}
fn contains_all(&self, bits: BitsIter) -> bool {
todo!()
}
}
}
Updated
First, thanks #Colonel Thirty Two give me a lot of information that I haven't mastered and help me fixed the problem of the iterator lifetime.
The cyclic-dependency I have solved by break the responsibility of the Storage into another struct RedisStorage without modify the bloom_filter module, but make the example bloated. Below is their relationships:
RedisCache -> BloomFilter -> Storage <---------------
| |
|-------> redis::Client <- RedisStorage ---<impl>---
I realized the ownership & lifetime system is not only used by borrow checker, but also Rustaceans need a bigger front design to obey the rules than in a GC language, e.g: java. Am I right?
Final Code
mod bloom_filter {
use std::{
hash::{Hash, Hasher},
marker::PhantomData,
};
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
pub trait Storage {
fn set(&mut self, bits: BitsIter);
fn contains_all(&self, bits: BitsIter) -> bool;
}
pub struct BloomFilter<T: Hash>(Box<dyn Storage>, PhantomData<T>);
impl<T: Hash> BloomFilter<T> {
#[allow(unused)]
pub fn new() -> BloomFilter<T> {
return Self::by(Box::new(ArrayStorage([0; 5000])));
struct ArrayStorage<const N: usize>([u8; N]);
impl<const N: usize> Storage for ArrayStorage<N> {
fn set(&mut self, bits: BitsIter) {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.for_each(|index| self.0[index] = 1);
}
fn contains_all(&self, bits: BitsIter) -> bool {
let size = self.0.len() as u64;
bits.map(|bit| (bit % size) as usize)
.all(|index| self.0[index] == 1)
}
}
}
pub fn by(storage: Box<dyn Storage>) -> BloomFilter<T> {
BloomFilter(storage, PhantomData)
}
pub fn add(&mut self, value: T) {
self.0.set(self.hash(value));
}
pub fn contains(&self, value: T) -> bool {
self.0.contains_all(self.hash(value))
}
fn hash<'a, H: Hash + 'a>(&self, value: H) -> BitsIter<'a> {
Box::new(
[3, 11, 31, 71, 131]
.into_iter()
.map(|salt| SimpleHasher(0, salt))
.map(move |mut hasher| hasher.hash(&value)),
)
}
}
struct SimpleHasher(u64, u64);
impl SimpleHasher {
fn hash<H: Hash>(&mut self, value: &H) -> u64 {
value.hash(self);
self.finish()
}
}
impl Hasher for SimpleHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
self.0 += bytes.iter().fold(0u64, |acc, k| acc * self.1 + *k as u64)
}
}
}
mod spi {
use super::bloom_filter::*;
use redis::{Client, Commands};
use std::{cell::RefCell, rc::Rc};
pub struct RedisCache<'a>(Rc<RefCell<Client>>, BloomFilter<&'a str>);
impl<'a> RedisCache<'a> {
pub fn new(client: Rc<RefCell<Client>>, filter: BloomFilter<&'a str>) -> RedisCache<'a> {
RedisCache(client, filter)
}
pub fn get<'f>(
&mut self,
key: &str,
load_value: fn() -> Option<&'f str>,
) -> Option<String> {
if self.1.contains(key) {
let mut redis = self.0.as_ref().borrow_mut();
if let Ok(value) = redis.get::<&str, String>(key) {
return Some(value);
}
if let Some(actual_value) = load_value() {
let _: () = redis.set(key, &actual_value).unwrap();
return Some(actual_value.into());
}
}
return None;
}
}
struct RedisStorage(Rc<RefCell<Client>>);
const BLOOM_FILTER_KEY: &str = "bloom_filter";
impl Storage for RedisStorage {
fn set(&mut self, bits: BitsIter) {
bits.for_each(|slot| {
let _: bool = self
.0
.as_ref()
.borrow_mut()
.setbit(BLOOM_FILTER_KEY, slot as usize, true)
.unwrap();
})
}
fn contains_all(&self, mut bits: BitsIter) -> bool {
bits.all(|slot| {
self.0
.as_ref()
.borrow_mut()
.getbit(BLOOM_FILTER_KEY, slot as usize)
.unwrap()
})
}
}
#[test]
fn prevent_cache_penetration_by_bloom_filter() {
let client = Rc::new(RefCell::new(Client::open("redis://localhost").unwrap()));
redis::cmd("FLUSHDB").execute(&mut *client.as_ref().borrow_mut());
let mut filter: BloomFilter<&str> = BloomFilter::by(Box::new(RedisStorage(client.clone())));
assert!(!filter.contains("Rust"));
filter.add("Rust");
assert!(filter.contains("Rust"));
let mut cache = RedisCache::new(client, filter);
assert_eq!(
cache.get("Rust", || Some("System Language")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Rust", || panic!("must never be called after cached")),
Some("System Language".to_string())
);
assert_eq!(
cache.get("Go", || panic!("reject to loading `Go` from external storage")),
None
);
}
}
pub type BitsIter = Box<dyn Iterator<Item = u64>>;
In this case, the object in the box must be valid for the 'static lifetime. This isn't the case for the iterator returned by hash - its limited to the lifetime of self.
Try replacing with:
pub type BitsIter<'a> = Box<dyn Iterator<Item = u64> + 'a>;
Or using generics instead of boxed trait objects.
So your RedisClient needs a BloomFilter, but the BloomFilter also needs the RedisClient?
Your BloomFilter should not use the RedisCache that itself uses the BloomFilter - that's a recipe for infinitely recursing calls (how do you know what calls to RedisCache::add should update the bloom filter and which calls are from the bloom filter?).
If you really have to, you need some form of shared ownership, like Rc or Arc. Your BloomFilter will also need to use a weak reference, or else the two objects will refer to each other and will never free.
I have a number of generic functions that need to return new instances of the generic. However, the fields in the generic are not known, but I need to get/set the field values to create the instance (a simple Default will not work). For primitive fields, I can update my struct, but for fields with Vector or HashMap types, I get the error:
the size for values of type `[usize]` cannot be known at compilation time
Here is a minimal working example of my issue:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6db1dd0b5982eca526725f4e5b423263
trait MyTrait {
fn id(&self) -> &usize;
fn id_mut(&mut self) -> &mut usize;
fn data(&self) -> &[usize];
fn data_mut(&mut self) -> &mut [usize];
}
#[derive(Debug)]
struct MyStruct {
id: usize,
data: Vec<usize>,
}
impl MyTrait for MyStruct {
fn id(&self) -> &usize {
&self.id
}
fn id_mut(&mut self) -> &mut usize {
&mut self.id
}
fn data(&self) -> &[usize] {
&self.data
}
fn data_mut(&mut self) -> &mut [usize] {
&mut self.data
}
}
impl Default for MyStruct {
fn default() -> MyStruct {
MyStruct {
id: 0,
data: vec![],
}
}
}
fn my_func<T: MyTrait + Default>() -> T {
let mut d = T::default();
// this correctly updates the struct field "id" to 26
*d.id_mut() = 26;
// this however, does not work. i get an error:
// the size for values of type `[usize]` cannot be known at compilation time
*d.data_mut() = vec![1, 2, 3].as_slice();
d
}
fn main() {
let _my_instance = my_func::<MyStruct>();
}
How can I create a generic function that returns an instance of the generic type?
For your Default instance of MyStruct, data is an empty Vec, but you are exposing it as a mutable slice. This is pretty meaningless because you can't change the length of a mutable slice; you can only mutate existing elements.
You will need to expose data as a &mut Vec<usize> instead, so that you can insert elements. The immutable getter can stay the same.
trait MyTrait {
fn id(&self) -> &usize;
fn id_mut(&mut self) -> &mut usize;
fn data(&self) -> &[usize];
fn data_mut(&mut self) -> &mut Vec<usize>;
}
And change the code that updates it:
fn my_func<T: MyTrait + Default>() -> T {
let mut d = T::default();
*d.id_mut() = 26;
*d.data_mut() = vec![1, 2, 3];
d
}
I want to make a struct which the text output can be either displayed on the console or stored in an internal buffer. If the text is buffered, then I need a method that gives back the text content.
For this aim I use a property named writer, which is dyn std::io::Write (wrapped into Rc<RefCell<>> because it is needed by my real code). Then on struct construction, I create either a io::stdout() instance or a Vec::<u8>::new() instance for this property.
use std::rc::Rc;
use std::cell::RefCell;
use std::io;
struct A {
// Rc<RefCell<>> is needed in my real code
writer: Rc<RefCell<dyn io::Write>>,
}
impl A {
pub fn new() -> Self {
Self { writer: Rc::new(RefCell::new(io::stdout())) }
}
pub fn new_buffered() -> Self {
Self { writer: Rc::new(RefCell::new(Vec::<u8>::new())) }
}
pub fn write(&self, s: &str) {
let mut writer = self.writer.borrow_mut();
writeln!(writer, "{}", s).unwrap();
}
/// Returns None if the struct is not buffered, otherwise a copy of the buffered output.
pub fn get_buffer(&self) -> Option<String> {
match GET_VEC_U8() { // <- Unable to implement this line
Some(vec_u8) => {
Some(String::from_utf8(vec_u8.clone()).unwrap())
},
None => None,
}
}
}
fn main() {
let a = A::new();
a.write("foo");
println!("Buffer: {:?}", a.get_buffer());
let b = A::new_buffered();
b.write("bar");
println!("Buffer: {:?}", b.get_buffer());
}
Question
But I can't figure out how to extract the text content (method get_buffer()), when the writer is Vec<u8>. How can I do it ?
My try
I tried to wrap the property into a Box:
struct A {
writer: Rc<RefCell<Box<dyn io::Write>>>,
}
then use Box::downcast() on it:
impl A {
pub fn get_buffer(&self) -> Option<String> {
let writer = self.writer.borrow();
match (*writer).downcast::<Vec<u8>>() {
Ok(vec_u8) => Some(String::from_utf8(vec_u8.clone()).unwrap()),
Err(_) => None,
}
}
}
but I get this error:
error[E0599]: no method named `downcast` found for struct `std::boxed::Box<dyn std::io::Write>` in the current scope
--> src/main.rs:27:25
|
27 | match (*writer).downcast::<Vec<u8>>() {
| ^^^^^^^^ method not found in `std::boxed::Box<dyn std::io::Write>`
As #SvenMarnach wrote in the comments, writing a custom trait depending on io::Write can be a solution
use std::rc::Rc;
use std::cell::RefCell;
use std::io::{self, Stdout};
trait MyWrite: io::Write {
fn get_buffer(&self) -> Option<String>;
}
impl MyWrite for Stdout {
fn get_buffer(&self) -> Option<String> {
None
}
}
impl MyWrite for Vec<u8> {
fn get_buffer(&self) -> Option<String> {
Some(String::from_utf8(self.clone()).unwrap())
}
}
struct A {
// Rc<RefCell<>> is needed in my real code
writer: Rc<RefCell<dyn MyWrite>>,
}
impl A {
pub fn new() -> Self {
Self { writer: Rc::new(RefCell::new(io::stdout())) }
}
pub fn new_buffered() -> Self {
Self { writer: Rc::new(RefCell::new(Vec::<u8>::new())) }
}
pub fn write(&self, s: &str) {
let mut writer = self.writer.borrow_mut();
writeln!(writer, "{}", s).unwrap();
}
/// Returns None if the struct is not buffered, otherwise a copy of the buffered output.
pub fn get_buffer(&self) -> Option<String> {
let writer = self.writer.borrow();
writer.get_buffer()
}
}
fn main() {
let a = A::new();
a.write("foo");
println!("Buffer: {:?}", a.get_buffer());
let b = A::new_buffered();
b.write("bar");
println!("Buffer: {:?}", b.get_buffer());
}
How can I reduce the lifetime of a closure?
I was trying to make a method, which returns an iterator related to self. I didn't want to make new struct or something, so I just made it return filters and maps, and confronted some borrow checker errors.
The following code was my first try.
fn f<'b>(&'b self) -> impl Iterator<Item = u8> {
(0..self.some_number())
.filter(|&i| self.some_bool_function(i))
.map(|i| i as u8)
}
The following code replicates my question.
struct A(bool);
impl A {
fn f<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {
(0..1).filter(|&i| self.0)
}
}
or even shorter,
fn g<'a>(t:&'a ()) -> impl 'a + FnMut() {
|| *t
}
This would not compile, because the closure may outlive self. I don't know how to make this work, without moving self.
If you return a closure, you must ensure that the closure has everything it needs - even after returning (i.e. after the (temporary) function parameters are popped from the stack).
Thus, I think you want to move the stuff you return into the closure:
impl A {
fn f<'a>(&'a self) -> impl Iterator<Item = u8> + 'a {
(0..1).filter(move |&i| self.0)
}
}
Resp.
fn g<'a>(t:&'a ()) -> impl 'a + FnMut() {
move || *t
}
Resp (extending your first example):
struct A(bool);
impl A {
fn some_number(&self) -> usize {
6
}
fn some_bool_function(&self, i: usize) -> bool {
i%2==0
}
fn f<'b>(&'b self) -> impl Iterator<Item = u8> + 'b {
(0..self.some_number())
.filter(move |&i| self.some_bool_function(i))
.map(|i| i as u8)
}
}
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)
I gave this some more thought and you can disregard my previous answer. That solution is unnecessarily complex. I got way to focused on returning &mut Self from put, even though that wasn't asked for at all. You can just return &mut RequestInfo from your put method and you're fine. The only price you pay is that you can't have a default implementation for put anymore.
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());
}
And now to the final step: You will have noticed that traits with methods that return Self can not be used as trait objects. That link has a solution to your problem: mark that method with where Self: Sized, so it doesn't appear on your trait object. But then you can't do your chaining with trait objects. This can be solved by implementing the method on Box<dyn RequestInfo> – which is not a trait object, but a Box. So, putting this all together:
pub trait RequestInfo {
fn logged_in(&self) -> bool;
fn put(&mut self, string: String) -> &mut Self
where Self: Sized {
self.put_internal(string);
self
}
fn put_internal(&mut self, string: String) {}
}
impl RequestInfo for Box<dyn RequestInfo> {
fn logged_in(&self) -> bool {
self.as_ref().logged_in()
}
}
struct LoggedOut {}
impl RequestInfo for LoggedOut {
fn logged_in(&self) -> bool {false}
}
struct LoggedIn {output: Vec<String>}
impl LoggedIn {
fn new() -> LoggedIn {
LoggedIn { output: Vec::new() }
}
}
impl RequestInfo for LoggedIn {
fn logged_in(&self) -> bool {true}
fn put_internal(&mut self, string: String) {
self.output.push(string);
}
}
fn get(flag: bool) -> Box<dyn RequestInfo> {
if flag {Box::new(LoggedIn::new())} else {Box::new(LoggedOut{})}
}
fn main() {
let mut info = get(true);
info.put("abc".to_string()).put("def".to_string());
}
You will have to decide if all of this is worth it for some chaining.