I've got this code snippet (playground link) where I'm basically trying to change a trait implementation to allow a state change for the struct it's applied to.
The current method signature is:
fn approve(self: Box<Self>) -> Box<dyn State>
, but I need to make it into something like
fn approve(&mut self: Box<Self>) -> Box<dyn State>
This doesn't compile. I've yet to see a Rust &mut self parameter definition along with a type, though I'm not sure why that would be an issue.
If I try:
fn approve(&mut self) -> Box<dyn State>
I get other compile-time errors when I try to return an unmodified self from the method.
For a little bit more context (before checking the playground), here are some relevant code bits:
trait State {
fn approve(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {
approve_count: u8,
}
impl State for Draft {
fn approve(self: Box<Self>) -> Box<dyn State> {
// self.approve_count += 1;
if self.approve_count == 2 {
Box::new(Approved {})
} else {
self
}
}
}
struct Approved {}
impl State for Approved { ... }
What I would like to do is be able to uncomment the self.approve_count += 1; line and have it work.
The correct syntax for a mutable reference is:
fn approve(self: &mut Box<Self>)
...but then you won't be able to return self as Box<dyn State> because you're only holding a reference to self.
If all you need is for self.approve_count += 1 to work, you don't need to switch to &mut self, you can simply declare mut self: Box<Self>:
impl State for Draft {
fn approve(mut self: Box<Self>) -> Box<dyn State> {
self.approve_count += 1;
if self.approve_count == 2 {
Box::new(Approved {})
} else {
self
}
}
...
}
Playground
That code is a bit suspect in that it modifies self.approved_count even in the case where the function returns a completely new Approved instance (and discards the just incremented value), but that may be fixed by moving the increment into the else clause and adjusting the test as appropriate.
Related
I've got code that looks (a little) like this:
struct OutputIterator<'r, 'i: 'r> {
input_handler: &'r mut InputHandler<'i>
}
impl<'r, 'i> Iterator for OutputIterator<'r, 'i> {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
self.input_handler.inputs.next().map(|x| x * 2)
}
}
struct InputHandler<'a> {
inputs: Box<dyn Iterator<Item = i32> + 'a>
}
impl<'a> InputHandler<'a> {
fn outputs<'b>(&'b mut self) -> OutputIterator<'b, 'a> {
OutputIterator { input_handler: self }
}
}
fn main() {
let mut input_handler = InputHandler {
inputs: Box::new(vec![1,2,3,4,5].into_iter())
};
for output in input_handler.outputs() {
println!("{}", output);
}
}
Basically, the user can supply an iterator of inputs, and then get an iterator of outputs (in my real code the connection between inputs and outputs is much more complex involving a bunch of internal state. Multiple inputs might go towards one output or vice-versa).
This works, but I would like to change it use impl Iterator both to hide the OutputIterator type and to allow for easier swapping out of the return type in testing with a fake. My best attempt at that changes the InputHandler impl like so:
impl<'a> InputHandler<'a> {
fn outputs<'b>(&'b mut self) -> impl Iterator<Item = i32> + 'b {
OutputIterator { input_handler: self }
}
}
Unfortunately, that gets me: error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
Is there a way to make this work? It's important for the interface that InputHandler take an iterator with some lifetime, and that obviously has to be passed on to the OutputIterator somehow, but I'd really like to abstract those details away from the caller. In principle, the caller should only have to worry about making sure that the inputs Iterator and InputHandler outlive the OutputIterator so I think the logical lifetime bound on the OutputIterator here is the smaller of those two? Any clarity on why this error is happening or how to fix it would be great!
In case it helps, here's a rust playground with the code in it.
Using a workaround from https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999, via https://stackoverflow.com/a/50548538/1757964:
trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
impl<'a> InputHandler<'a> {
fn outputs<'b>(&'b mut self) -> impl Iterator<Item = i32> + Captures<'a> + 'b {
OutputIterator { input_handler: self }
}
}
In this piece of code:
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
pub fn content(&self) -> &str {
""
}
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
}
struct PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
}
there is a call to take(); the book says:
To consume the old state, the request_review method needs to take ownership of the state value. This is where the Option in the state field of Post comes in: we call the take method to take the Some value out of the state field and leave a None in its place.
We need to set state to None temporarily rather than setting it directly with code like self.state = self.state.request_review(); to get ownership of the state value. This ensures Post can’t use the old state value after we’ve transformed it into a new state.
How is it possible that Post uses its old state if we set it directly?
If you code like this:
pub struct Post {
state: Box<dyn State>,
content: String,
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
impl Post {
// ...
pub fn request_review(&mut self) {
self.state = self.state.request_review();
}
// ...
}
You will get a compiler error:
self.state = self.state.request_review();
^^^^^^ move occurs because `self.state` has type `std::boxed::Box<dyn State>`, which does not implement the `Copy` trait'.
This is because calling State::request_review will move Box<self>, which is allocated on heap, and Rust doesn't allow you to just move values away from heap unless you implement Copy, otherwise what's left there? The book uses Option::take() to move ownership out and leave None on the place.
If request_review panic, it will lead to free the Box twice, first in request_review and then when the Option is freed.
Quote from the book; bold font my formatting
we call the take method to take the Some value out of the state field
and leave a None in its place, because Rust doesn’t let us have
unpopulated fields in structs.
As for move and assignment in the same statement, looks like Rust does not detect it as valid.
I have a Rust method that returns a Result<_, MyError>. This method is run on a State struct and MyError has a lifetime specifier 'a because it needs to keep some &strs.
I'm trying to write a trait like this:
trait MyTrait {
type Error;
fn work(&self) -> Result<(), Self::Error>;
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work() // returns Result<(), MyError> but state doesn't live long enough
}
}
How can I get around this error? Should I change MyError to keep String instead of &'a str? Should I keep the state inside of MyImpl? Is this trait well-defined?
I want to create a State for every run of do().
Here is an MCVE:
enum MyError<'a> {
Some(&'a str),
}
trait MyTrait {
type Error;
fn work(&self) -> Result<(), Self::Error>;
}
struct MyImpl<'a> {
pub some_string: &'a str,
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work() // returns Result<(), MyError> but state doesn't live long enough
}
}
struct State;
impl State {
pub fn new() -> State {
State
}
pub fn work(&self) -> Result<(), MyError> {
Err(MyError::Some("hi"))
}
}
fn main() {}
(Playground)
The problem is that according to the signature of State::work() the lifetime parameter of MyError becomes tied to that of &self reference:
// without lifetime elision
pub fn work<'a>(&'a self) -> Result<(), MyError<'a>>
And afterwards this value is returned in MyImpl::work():
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work()
}
The problem is, lifetime parameter 'a in impl<'a> MyTrait for MyImpl<'a> denotes a lifetime which is strictly larger than that of MyError returned by State::work(). Why it is so? Well, let's look at MyImpl::work() again:
fn work(&self) -> Result<(), MyError<'a>> {
let state = State::new();
state.work()
}
Remember that State::work(&self) returns a MyError with lifetime tied to that of &self, that is, in this particular case it will be the lifetime of state. The latter, being a local variable, is destroyed immediately after work() returns.
However, 'a in impl<'a> MyTrait for MyImpl<'a> denotes the lifetime of a string slice stored in MyImpl (that is, in self). Naturally, because MyImpl::work() can be called at all, it means that the value it is called at is in a valid state and holds a slice which is alive. Therefore, its lifetime is larger than anything which can be created inside MyImpl::work(). So it is unsound to return anything which is not derived from this string slice inside MyImpl; for example, this is valid:
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError<'a>;
fn work(&self) -> Result<(), MyError<'a>> {
Err(MyError::Some(self.some_string))
}
}
Now the lifetime of MyError value is exactly that of self.some_string, and the borrow checker becomes happy.
Now, what options are there? First, the simplest approach would be to store an owned String inside MyError:
enum MyError {
Some(String)
}
impl<'a> MyTrait for MyImpl<'a> {
type Error = MyError;
fn work(&self) -> Result<(), MyError> {
let state = State::new();
state.work()
}
}
struct State;
impl State {
pub fn new() -> State {
State
}
pub fn work(&self) -> Result<(), MyError> {
Err(MyError::Some("hi".into()))
}
}
This, I believe, is the most idiomatic and the most flexible approach. It is actually very uncommon to have non-self-sufficient error values; I think I've never seen one before. Another alternative would be to use &'static str:
enum MyError {
Some(&'static str)
}
struct State;
impl State {
pub fn new() -> State {
State
}
pub fn work(&self) -> Result<(), MyError> {
Err(MyError::Some("hi"))
}
}
This approach won't allow you to create error messages dynamically (you can only use string literals for your error messages) but it is more efficient because it does not require allocations for the unhappy path in your program and it may be sufficient for your use cases.
I'm trying to make two structs that operate on an underlying dataset; one providing immutable "read" operations, the other allowing modification. For this to work, I need to be able to use the read functions from within the modifying object - as such I create a temporary new read object within the modifier function with a view onto the underlying data.
Here's some code:
struct Read<'db> {
x: &'db i32
}
impl<'db> Read<'db> {
pub fn get(&'db self) -> &'db i32 { self.x }
}
struct Write<'db> {
x: &'db mut i32
}
impl<'db> Write<'db> {
fn new(x: &mut i32) -> Write { Write{x: x} }
fn as_read(&'db self) -> Read<'db> {
Read{x: self.x}
}
pub fn get(&'db self) -> &'db i32 { self.as_read().get() }
}
fn main() {
let mut x = 69i32;
let y = Write::new(&mut x);
println!("{}", y.get());
}
It doesn't compile - it seems that despite my best efforts, the lifetime of the reference returned from Read::get is bound to the Write::get's scope, rather than the Write's 'db lifetime. How can I make it compile? (And, is what I want to do possible? Is it the simplest/most concise way of doing it?)
The point the compiler is trying to get across is that &'db self actually means self: &'db Write<'db>. This means that you tie the reference AND the type to the same lifetime. What you actually want in your case is self: &'a Write<'db> where 'a lives just for the as_read function. To be able to return a 'db reference from a 'a reference, you need to specify that 'a lives at least as long as 'db by constraining 'a: 'db.
fn as_read<'a: 'db>(self: &'a Write<'db>) -> Read<'db> {
Read{x: self.x}
}
pub fn get<'a: 'db>(self: &'a Write<'db>) -> &'db i32 { self.as_read().get() }
or more concisely
fn as_read<'a: 'db>(&'a self) -> Read<'db> {
Read{x: self.x}
}
pub fn get<'a: 'db>(&'a self) -> &'db i32 { self.as_read().get() }
Try it out in the Playground
For reference, I'm using Rust 0.7.
I'm trying to create a stack implementation using an owned linked list and I'm running into trouble.
trait Stack<T> {
fn push(&mut self, item : T);
fn pop(&mut self) -> Option<T>;
}
enum Chain<T> {
Link(T, ~Chain<T>),
Break
}
impl<T> Stack<T> for ~Chain<T> {
fn push(&mut self, item : T) {
*self = ~Link(item, *self);
}
fn pop(&mut self) -> Option<T> {
None
}
}
When I try to rustc stack.rs I get the following error:
stack.rs:13:28: 13:34 error: cannot move out of dereference of & pointer
stack.rs:13 *self = ~Link(item, *self);
^~~~~~
I don't know how I could overcome this or what I could do differently to allow this. It seems like I should be able to create this data structure without using managed pointers, but I haven't seen a lot of documentation on this sort of thing.
Either assignment from self (which I think includes constructing a new thing out of it, as in the case of Link(item, *self) implies a move. This means that in the process of constructing the new Link that self becomes unusable, because:
"After a value has been moved, it can no longer be used from the source location and will not be destroyed there."
The Right Way™ is probably best documented by what's done in this example in the stdlib. It's a doubly linked list, and it is managed, but it's mutable, and I hope copy free. There's also list of useful container types, too.
I did manage to get this immutable version of your datastructure working, however.
trait Stack<T> {
fn push(self, item : T) -> Self;
fn pop(self) -> Option<(T, Self)>;
fn new() -> Self;
}
#[deriving(Eq, ToStr)]
enum Chain<T> {
Link(T, ~Chain<T>),
Break
}
impl<T> Stack<T> for Chain<T> {
fn push(self, item : T) -> Chain<T> {
Link(item, ~self)
}
fn pop(self) -> Option<(T, Chain<T>)> {
match self {
Link(item, ~new_self) => Some((item, new_self)),
Break => None
}
}
fn new() -> Chain<T> {
Break
}
}
fn main() {
let b : ~Chain<int> = ~Stack::new();
println(b.push(1).push(2).push(3).to_str());
}