How to manipulate a content variable from inside struct's function? - rust

I'm new to Rust. I followed the tutorial from their doc here. In Listing 5-13, we have an implementation of struct that prints an area.
My question is how to manipulate self.width or self.height from within the struct's function, such as this to be possible:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
// I need to use mut self instead of &self so I can access self variable here
// but since I pass the ownership into this function, the prinln!
// throws an error: "value borrowed here after move"
// but If I don't do that, the set_width cannot manipulate the width
fn set_width(mut self, width: u32) {
self.width = width;
}
}
fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
rect1.set_width(50);
// value borrowed here after move error
println!("The area of the rectangle is {} square pixels.", rect1.area());
}

Taking self, whether by mut or not, means the method consumes self. If you want to modify the structure in-place, you need &mut self. In fact this is covered by the text below 5.13:
We’ve chosen &self here for the same reason we used &Rectangle in the function version: we don’t want to take ownership, and we just want to read the data in the struct, not write to it. If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self as the first parameter. Having a method that takes ownership of the instance by using just self as the first parameter is rare; this technique is usually used when the method transforms self into something else and you want to prevent the caller from using the original instance after the transformation.
(emphasis mine)
&mut having been covered by the previous section 4.2.
self is both magical and not, it's syntactic sugar for a variation of self: <something>Self, and allows calling the method on an instance (inst.method()), but that aside it follows the normal Rust rule with respect to ownership and borrowing.

Related

implement a function on a struct A that borrows another struct B?

In the process of an entity-component system, I'm having this issue where I want all my objects in my scene to be able to use methods on the scene as mutable.
However, I don't think keeping a reference to the scene is a good idea, as the scene is the structure containing the objects (so it would make a cycling reference), and I can't have multiple mutables references.
The idea that i got is that my objects have a function that borrows the scene : each time I want to do something on the scene from my object, I borrow the scene and then drop the borrow.
This is what I tried so far :
This is my Scene structure
pub struct GameScene {
// array of all objects
objects: Vec<GearObject>,
components: ComponentTable,
}
And there is my object :
pub struct GearObject<'o, 's:'o> {
transform: Transform,
id: u32,
get_scene: &'o dyn Fn() -> &'s mut GameScene,
}
impl<'s:'o, 'o> GearObject<'o, 's> {
pub fn empty(id: u32, scene_borrow: &'s mut GameScene) -> GearObject<'o, 's> {
// creates an empty gearObject
return GearObject {
id: id,
transform: Transform::origin(),
get_scene: &|| scene_borrow,
};
}
}
The idea was that my 'get_scene' would be a function that could borrow the scene
However, I'm not sure if I'm doing this correctly, the code doesn't even compile ("cannot infer an appropriate lifetime for lifetime parameter 's due to conflicting requirements")
Does this keeps a reference to my scene, or is it doing what I was expecting, only borrowing the scene when called?
Also, Why do I have a lifetime issue here ? am I not guaranting that my scene lives longer than my function to get it ?

How do I return a reference to an iterator using conservative_impl_trait?

I have a petgraph::Graph structure onto which I have imposed a tree structure by giving every node weight a parent_edge_idx which is an Option<EdgeIdx> of the edge that connects from its parent to itself.
I need to iterate over a node's children. I need the edge weight of the connecting edge and the node weight of the child.
I wanted to factor that iteration into a helper function that returns a reference to an Iterator<Item = (EdgeIdx, NodeIdx)>. I want to do this cost-free; since I have to borrow self.search_tree in order to do this, the iterator is only valid for the lifetime of self.
Is this a reasonable function to want to write?
Is it possible to write this function?
Any gated features are ok; I'm on nightly.
fn children<'a>(
&'a mut self,
node_idx: NodeIdx,
) -> &'a impl Iterator<Item = (EdgeIdx, NodeIdx)> {
&self.search_tree.neighbors(node_idx).map(|child_idx| {
let node = self.search_tree.node_weight(child_idx).unwrap();
let edge_idx = node.parent_edge_idx.unwrap();
(edge_idx, child_idx)
})
}
How to return an iterator is already covered in this question.
Note that you don't need to return a reference: you want to return an iterator value directly, so if we remove the first & in both the method body and the return type, that's closer to what we need.
We will use impl Iterator so that we don't have to name the actual iterator type exactly. Just note (code below) that we need to use the impl Iterator<..> + 'a syntax, which means that the (anonymous) iterator contains references valid to use for at least the lifetime 'a.
We can't use &mut self here! Note that we need to borrow self.search_tree twice: once for the .neighbors() iterator and once for the self.search_tree that's used in the map closure. Multiple borrowing is incompatible with mutable references.
We put move as the capture mode on the closure, so that it captures the self reference directly, and not by reference (this is important so that we can return the iterator and the closure.
Petgraph specific, but we replace g.node_weight(node_index).unwrap() with just &g[node_index] which is equivalent, but the latter is easier to read.
Here is a reproduction of your code, but with modifications along 1-5 to make it compile:
#![feature(conservative_impl_trait)]
extern crate petgraph;
use petgraph::Graph;
use petgraph::graph::{NodeIndex, EdgeIndex};
struct Foo {
search_tree: Graph<Node, i32>,
}
struct Node {
parent_edge_idx: Option<EdgeIndex>,
}
impl Foo {
fn children<'a>(&'a self, node_idx: NodeIndex)
-> impl Iterator<Item = (EdgeIndex, NodeIndex)> + 'a
{
self.search_tree.neighbors(node_idx).map(move |child_idx| {
let node = &self.search_tree[child_idx];
let edge_idx = node.parent_edge_idx.unwrap();
(edge_idx, child_idx)
})
}
}

Can a type know when a mutable borrow to itself has ended?

I have a struct and I want to call one of the struct's methods every time a mutable borrow to it has ended. To do so, I would need to know when the mutable borrow to it has been dropped. How can this be done?
Disclaimer: The answer that follows describes a possible solution, but it's not a very good one, as described by this comment from Sebastien Redl:
[T]his is a bad way of trying to maintain invariants. Mostly because dropping the reference can be suppressed with mem::forget. This is fine for RefCell, where if you don't drop the ref, you will simply eventually panic because you didn't release the dynamic borrow, but it is bad if violating the "fraction is in shortest form" invariant leads to weird results or subtle performance issues down the line, and it is catastrophic if you need to maintain the "thread doesn't outlive variables in the current scope" invariant.
Nevertheless, it's possible to use a temporary struct as a "staging area" that updates the referent when it's dropped, and thus maintain the invariant correctly; however, that version basically amounts to making a proper wrapper type and a kind of weird way to use it. The best way to solve this problem is through an opaque wrapper struct that doesn't expose its internals except through methods that definitely maintain the invariant.
Without further ado, the original answer:
Not exactly... but pretty close. We can use RefCell<T> as a model for how this can be done. It's a bit of an abstract question, but I'll use a concrete example to demonstrate. (This won't be a complete example, but something to show the general principles.)
Let's say you want to make a Fraction struct that is always in simplest form (fully reduced, e.g. 3/5 instead of 6/10). You write a struct RawFraction that will contain the bare data. RawFraction instances are not always in simplest form, but they have a method fn reduce(&mut self) that reduces them.
Now you need a smart pointer type that you will always use to mutate the RawFraction, which calls .reduce() on the pointed-to struct when it's dropped. Let's call it RefMut, because that's the naming scheme RefCell uses. You implement Deref<Target = RawFraction>, DerefMut, and Drop on it, something like this:
pub struct RefMut<'a>(&'a mut RawFraction);
impl<'a> Deref for RefMut<'a> {
type Target = RawFraction;
fn deref(&self) -> &RawFraction {
self.0
}
}
impl<'a> DerefMut for RefMut<'a> {
fn deref_mut(&mut self) -> &mut RawFraction {
self.0
}
}
impl<'a> Drop for RefMut<'a> {
fn drop(&mut self) {
self.0.reduce();
}
}
Now, whenever you have a RefMut to a RawFraction and drop it, you know the RawFraction will be in simplest form afterwards. All you need to do at this point is ensure that RefMut is the only way to get &mut access to the RawFraction part of a Fraction.
pub struct Fraction(RawFraction);
impl Fraction {
pub fn new(numerator: i32, denominator: i32) -> Self {
// create a RawFraction, reduce it and wrap it up
}
pub fn borrow_mut(&mut self) -> RefMut {
RefMut(&mut self.0)
}
}
Pay attention to the pub markings (and lack thereof): I'm using those to ensure the soundness of the exposed interface. All three types should be placed in a module by themselves. It would be incorrect to mark the RawFraction field pub inside Fraction, since then it would be possible (for code outside the module) to create an unreduced Fraction without using new or get a &mut RawFraction without going through RefMut.
Supposing all this code is placed in a module named frac, you can use it something like this (assuming Fraction implements Display):
let f = frac::Fraction::new(3, 10);
println!("{}", f); // prints 3/10
f.borrow_mut().numerator += 3;
println!("{}", f); // prints 3/5
The types encode the invariant: Wherever you have Fraction, you can know that it's fully reduced. When you have a RawFraction, &RawFraction, etc., you can't be sure. If you want, you may also make RawFraction's fields non-pub, so that you can't get an unreduced fraction at all except by calling borrow_mut on a Fraction.
Basically the same thing is done in RefCell. There you want to reduce the runtime borrow-count when a borrow ends. Here you want to perform an arbitrary action.
So let's re-use the concept of writing a function that returns a wrapped reference:
struct Data {
content: i32,
}
impl Data {
fn borrow_mut(&mut self) -> DataRef {
println!("borrowing");
DataRef { data: self }
}
fn check_after_borrow(&self) {
if self.content > 50 {
println!("Hey, content should be <= {:?}!", 50);
}
}
}
struct DataRef<'a> {
data: &'a mut Data
}
impl<'a> Drop for DataRef<'a> {
fn drop(&mut self) {
println!("borrow ends");
self.data.check_after_borrow()
}
}
fn main() {
let mut d = Data { content: 42 };
println!("content is {}", d.content);
{
let b = d.borrow_mut();
//let c = &d; // Compiler won't let you have another borrow at the same time
b.data.content = 123;
println!("content set to {}", b.data.content);
} // borrow ends here
println!("content is now {}", d.content);
}
This results in the following output:
content is 42
borrowing
content set to 123
borrow ends
Hey, content should be <= 50!
content is now 123
Be aware that you can still obtain an unchecked mutable borrow with e.g. let c = &mut d;. This will be silently dropped without calling check_after_borrow.

How can I use lifetime bounds to solve "reference must be valid for the static lifetime"

I am a Rust beginner and I can’t get the following code to compile.
What I want is to store several traits in a vector and each of the traits should also have read-only access to a borrowed variable.
I am guessing I have to use „Lifetime bounds“ - like discussed in this thread - because if I comment out lines 60-68, the code compiles fine.
Can somebody please explain how to use „lifetime bounds“ - if this is the way to solve the problem - or is this not the Rust way to solve the problem? If there is a better way to achieve what I’m trying to do I’m glad to change my approach to the problem.
The code which doesn’t compile is here and on rust-playground.
struct PixelImageSimple<'a> {
pixels: &'a Vec<i32>,
width: i32,
height: i32,
}
trait ImageOperation<'a> {
fn execute_op(&self);
}
struct ImageOperationSharpen<'a> {
val: i32,
bitmapdata: &'a PixelImageSimple<'a>
}
impl<'a> ImageOperation<'a> for ImageOperationSharpen<'a> {
fn execute_op(&self) {
println!("ImageOperationSharpen - val = {}, width = {}, height = {}, pixels = {:?}",
&self.val, &self.bitmapdata.width, &self.bitmapdata.height,&self.bitmapdata.pixels);
}
}
struct ImageOperationRotate<'a> {
angle: f64,
bitmapdata: &'a PixelImageSimple<'a>
}
impl<'a> ImageOperation<'a> for ImageOperationRotate<'a> {
fn execute_op(&self) {
println!("ImageOperationRotate - angle = {}, width = {}, height = {}, pixels = {:?}",
&self.angle, &self.bitmapdata.width, &self.bitmapdata.height,&self.bitmapdata.pixels);
}
}
struct Image<'a> {
image_operations: Vec<Box<ImageOperation<'a>>>
}
impl<'a> Image<'a> {
fn new() -> Image<'a> {
Image { image_operations: vec![] }
}
fn add_op(&mut self, image_ops: Box<ImageOperation<'a>>) {
self.image_operations.push(image_ops);
}
}
fn main () {
let bitmapdata = vec![1,2,3];
let bitmap = PixelImageSimple { pixels: &bitmapdata, width: 222, height:334 };
let sharpen = ImageOperationSharpen { val: 34, bitmapdata: &bitmap };
let rotate = ImageOperationRotate { angle: 13.32, bitmapdata: &bitmap };
let box_sharpen = Box::new(sharpen);
let box_rotate = Box::new(rotate);
let mut image = Image::new();
image.add_op(box_sharpen);
image.add_op(box_rotate);
println!("execute_op()");
for imageops in image.image_operations.iter() {
imageops.execute_op();
}
}
I get 3 errors for variable 'bitmapdata' and 'bitmap' twice.
As I mentioned above: the code compiles fine without lines 60-68 but results in a compiler error with those lines.
Interesting thing: the compilers hint message note:
reference must be valid for the static lifetime...
So the compiler wants a static lifetime? (replacing 'a with 'static in the code didn't help)
lifetime_bounds.rs:52:46: 52:56 error: `bitmapdata` does not live long enough
lifetime_bounds.rs:52 let bitmap = PixelImageSimple { pixels: &bitmapdata, width: 222, height:334 };
^~~~~~~~~~
note: reference must be valid for the static lifetime...
lifetime_bounds.rs:50:34: 69:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 50:33
lifetime_bounds.rs:50 let bitmapdata = vec![1,2,3];
lifetime_bounds.rs:51
lifetime_bounds.rs:52 let bitmap = PixelImageSimple { pixels: &bitmapdata, width: 222, height:334 };
lifetime_bounds.rs:53
lifetime_bounds.rs:54 let sharpen = ImageOperationSharpen { val: 34, bitmapdata: &bitmap };
lifetime_bounds.rs:55 let rotate = ImageOperationRotate { angle: 13.32, bitmapdata: &bitmap };
...
As an alternative approach I tried a solution using a collection
type CollectionOfImageOperations<'a> = Vec<&'a (ImageOperation<'a> + 'a)>;
but this gave me compile errors which made less sense to me than in the approach above. (It seems like I can only push one trait object to the vector - but why) - see rust-playground for the code and error.
Any hints & tips are welcome and appreciated.
You've run afoul of lifetime elision. When in doubt, write it out!
Note: the comments are because what I'm adding here is not valid Rust syntax. Also note that what follows is not entirely accurate, to avoid being bogged down in details.
fn main () {
/* Lifetimes come from storage, so we'll annotate relevant
variables with lifetimes. We're not defining lifetimes,
we're just assigning names to the lifetimes that the compiler
will work out during borrow checking. */
/* 'a: */ let bitmapdata = vec![1,2,3];
/* We'll also substitute the lifetimes into the types of the
variables and expressions we talk about. Again, you normally
couldn't do this, because you can't name lifetimes *within*
a function. */
/* 'b: */ let bitmap/*: PixelImageSimple<'a> */
= PixelImageSimple {
pixels: &/*'a*/bitmapdata,
width: 222,
height: 334
};
/* We have to pick *one* lifetime here, so we'll pick the
"narrowest" lifetime. We'll cheat here and "assume" that
'a: 'b (read: "'a outlives 'b"); or, in other words, that
'b < 'a (read: "'b is no longer than 'a"). */
let sharpen/*: ImageOperationSharpen<'b> as 'b < 'a */
= ImageOperationSharpen {
val: 34,
bitmapdata: &/*'b*/bitmap/*: PixelImageSimple<'a>*/
};
let box_sharpen/*: Box<ImageOperationSharpen<'b>>*/
= Box::new(sharpen);
/* We'll introduce `'x` here, because it's not immediately clear
what this lifetime should be. The compiler will infer it
from whatever constraints it's been placed under for us. */
/* 'c: */ let mut image/*: Image<'x>*/
= Image::new();
/* Wait, where did `'y` come from? Lifetime elision. When
you're dealing with trait objects, the compiler *must* know
for how long said object is valid. Normally, the compiler
would just look at a type's lifetime parameters, but a trait
object *throws that information away*. As a result, it
needs to preserve this information external to the trait.
This is done using the `Trait + 'k` syntax, where `'k` is
a lifetime that bounds *all* possible implementations of
the trait *in this position*.
This statement is implicit in the original code, but I'm
adding it here to make things explicit. I've also included
the `impl` to denote how the lifetimes transfer around during
the cast. */
let box_sharpen/*: Box<ImageOperation<'b> + 'y>*/
/*where impl<'l> ImageOperation<'l> for ImageOperationSharpen<'l>*/
= box_sharpen/*: Box<ImageOperationRotate<'b>>*/
as Box<ImageOperation/*<'b> + 'y*/>;
/* The only change here is that I *explicitly* borrow `image`
in order to make all the lifetimes involved explicit. In
addition, we now have all the information necessary to work
out what the inferred lifetimes above should be. */
(&/*'c */mut image).add_op(
box_sharpen/* as Box<ImageOperation<'b> + 'y>*/
);
/*where impl<'l> Image::<'l>::add_op<'m>(&'m mut self,
image_ops: Box<ImageOperation<'l> + 'z>)*/
/*implies 'l = 'b, 'm = 'c, 'z = 'y, 'x = 'l = 'b*/
}
All the lifetimes check out... except for 'z = 'y.
What is 'z? Whatever it is, it determines the minimum
lifetime of all values that implement ImageOperation.
What's reasonable? You're talking about a Box of something,
so what would make sense? The narrowest possible lifetime, or
the widest? The narrowest would render Box<Trait> almost
unusable, so it must be the widest. The widest is 'static,
therefore 'z = 'static.
But wait... if you have Box<ImageOperation<'q> + 'static>, the
type that implements ImageOperation<'q> must live at least
as long as the 'static lifetime... which means that 'q must
also be 'static.
By this reasoning, 'x = 'l = 'b = 'static. But this implies
that when we initialise sharpen, we do so with the following
expression:
bitmapdata: &'static bitmap: PixelImageSimple<'a>
But that can't be right; you can't have a reference to something
that outlives the something being referenced. That means we
require 'a to outlive 'static... which means 'a is
also 'static.
But 'a is a stack frame; it cannot be 'static!
Thus, the program is not sound.
... so what if we just explicitly tell the compiler that we
don't want a + 'static bound on our trait objects?
struct Image<'a> {
image_operations: Vec<Box<ImageOperation<'a> + 'a>>
}
impl<'a> Image<'a> {
fn new() -> Image<'a> {
Image { image_operations: vec![] }
}
fn add_op(&mut self, image_ops: Box<ImageOperation<'a> + 'a>) {
self.image_operations.push(image_ops);
}
}
// ...
fn main() {
// ...
(&/*'c */mut image).add_op(
box_sharpen/* as Box<ImageOperation<'b> + 'y>*/
);
/*where impl<'l> Image::<'l>::add_op<'m>(&'m mut self,
image_ops: Box<ImageOperation<'l> + 'z>)*/
/*implies 'l = 'b, 'm = 'c, 'z = 'y, 'x = 'l = 'b*/
}
And it now compiles.
Addendum (suggested by aatch): additionally, the lifetime on ImageOperation itself seems misplaced. You aren't using it for anything, and it isn't necessary for the code to work. In that case, you end up dealing with Box<ImageOperation + 'a>s, which is an even better demonstration of why you need trait object lifetime bounds.
I'm assuming you have encountered the XY-Problem (Trying to figure out the solution to an issue that is unrelated to your real problem)
Rust cannot reason about heap-lifetimes. The Box and Vec (through vec![]) allocations are heap allocations. They could just as well live for the entirety of the program, or just for a single scope. Rust does not know anything about the lifetime of these allocations, except that any references they contain need to outlive the heap object you just allocated.
You want multiple ImageOperation objects to have a reference to the bitmap object, and you want to be able to let those ImageOperation objects be moved onto the heap. The simplest solution is to get rid of all references and lifetimes and use a combination of moving and reference counted Rc boxes.
Lets start with the PixelImageSimple type. We remove the lifetimes and references.
struct PixelImageSimple {
pixels: Vec<i32>,
width: i32,
height: i32,
}
now you have an object that owns a Vec. No other object can control that Vec except through controlling the PixelImageSimple object.
Onto the ImageOperation trait. The lifetime 'a doesn't show up in the body of the trait. You can remove it without consequences.
trait ImageOperation {
fn execute_op(&self);
}
Now it gets interesting. You want the ImageOperationSharpen type to know about the PixelImageSimple but other types should also have access to the same PixelImageSimple object. This is where reference counted boxes come into play. An Rc allows multiple immutable "references" to the same object which all own the object in a way. You can clone an Rc to create more boxes pointing to the same object. Internally a counter keeps track of the number of Rc pointing to that object. Whenever an Rc gets dropped (its scope ends or you explicitly call drop) the counter is decreased. When it reaches zero, the object is actually dropped and the memory is freed.
struct ImageOperationSharpen {
val: i32,
bitmapdata: Rc<PixelImageSimple>
}
The ImageOperation implementation is exactly the same, just with all lifetimes removed.
impl ImageOperation for ImageOperationSharpen {
fn execute_op(&self) {
println!("ImageOperationSharpen - val = {}, width = {}, height = {}, pixels = {:?}",
&self.val, &self.bitmapdata.width, &self.bitmapdata.height,&self.bitmapdata.pixels);
}
}
We now repeat this for ImageOperationRotate:
struct ImageOperationRotate {
angle: f64,
bitmapdata: Rc<PixelImageSimple>
}
impl ImageOperation for ImageOperationRotate {
fn execute_op(&self) {
println!("ImageOperationRotate - angle = {}, width = {}, height = {}, pixels = {:?}",
&self.angle, &self.bitmapdata.width, &self.bitmapdata.height,&self.bitmapdata.pixels);
}
}
Here I'm a little confused as to what you are trying to do. Do you want to modify the PixelImageSimple when you call execute_op? This isn't possible as both the references you had and the Rc don't allow modification of the pointed-to object. See at the bottom of this answer for a solution.
struct Image {
image_operations: Vec<Box<ImageOperation>>
}
impl Image {
fn new() -> Image {
Image { image_operations: vec![] }
}
fn add_op(&mut self, image_ops: Box<ImageOperation>) {
self.image_operations.push(image_ops);
}
}
The changes require some minimal changes, mostly removal of the & operator and adding the Rc::new call.
fn main () {
let bitmapdata = vec![1,2,3];
let bitmap = Rc::new(PixelImageSimple { pixels: bitmapdata, width: 222, height:334 });
let sharpen = ImageOperationSharpen { val: 34, bitmapdata: bitmap.clone() };
// since we don't create any more ImageOperations, we can move the
// Rc directly into this object. otherwise we'd also clone it.
let rotate = ImageOperationRotate { angle: 13.32, bitmapdata: bitmap };
let box_sharpen = Box::new(sharpen);
let box_rotate = Box::new(rotate);
let mut image = Image::new();
image.add_op(box_sharpen);
image.add_op(box_rotate);
println!("execute_op()");
for imageops in image.image_operations.iter() {
imageops.execute_op();
}
}
A related solution
If you want to modify the PixelImageSimple object in every operation, I'd structure everything a little differently. First change the ImageOperation trait's execute_op function to also take an &mut PixelImageSimple.
trait ImageOperation {
fn execute_op(&self, bitmap: &mut PixelImageSimple);
}
Then remove all the Rc<PixelImageSimple> from the *ImageOperation types, and instead add a PixelImageSimple field to the Image type.
struct ImageOperationSharpen {
val: i32,
}
impl ImageOperation for ImageOperationSharpen {
fn execute_op(&self, bitmap: &mut PixelImageSimple) {
// you could modify bitmap now.
println!("ImageOperationSharpen - val = {}, width = {}, height = {}, pixels = {:?}",
self.val, bitmap.width, bitmap.height, bitmap.pixels);
}
}
struct ImageOperationRotate {
angle: f64,
}
impl ImageOperation for ImageOperationRotate {
fn execute_op(&self, bitmap: &mut PixelImageSimple) {
println!("ImageOperationRotate - angle = {}, width = {}, height = {}, pixels = {:?}",
self.angle, bitmap.width, bitmap.height, bitmap.pixels);
}
}
struct Image {
image_operations: Vec<Box<ImageOperation>>
bitmap: PixelImageSimple,
}
impl Image {
fn new(bitmap: PixelImageSimple) -> Image {
Image {
image_operations: vec![],
bitmap: bitmap,
}
}
fn add_op(&mut self, image_ops: Box<ImageOperation>) {
self.image_operations.push(image_ops);
}
fn apply_ops(&mut self) {
// iterate over the ops and automatically remove them
for op in self.image_operations.drain() {
op.execute_op(&mut self.bitmap);
}
}
}

Build object with specific lifetime

I have a problem that I don't know exactly how to model into Rust, in regard with ownership, lifetime and all that.
I have a large struct:
struct LargeStruct {
x: f32,
n: i32,
// lot of other fields.
}
The struct being large, I want to avoid copies, and therefore I carry around pointers to it.
I have a foo function that takes a pointer to LargeStruct and a f32 value. If this value is larger than the field x, I want to create a new object with x set to this value, and returns it. If it is not larger, then I want to return the original pointer itself.
I naively implemented it like this:
fn foo(object: &LargeStruct, y: f32) -> &LargeStruct {
if object.x < y {
LargeStruct {
x: y,
n: object.n,
// ...
}
}
else {
object
}
}
But it does not work: the two branches of the if do no return the same type. In the first case, I actually return a LargeStruct, and in the second I return a &LargeStruct. If I modify the object construction to take its pointer:
&LargeStruct {
then it doesn't work either: the lifetime of the object constructed is too short, so I can not return that from the function.
If I try to build the object on the heap:
~LargeStruct {
I have now another compilation error:
if and else have incompatible types: expected ~LargeStruct but found
&LargeStruct (expected &-ptr but found ~-ptr)
I tried to specify a lifetime in the function signature:
fn foo<'a>(object: &'a LargeStruct, y: f32) -> &'a LargeStruct {
But it does not help: I don't know how to build a new LargeStruct with the same lifetime.
I am calling this function like this:
fn main() {
let object = LargeStruct{
x: 1.0,
n: 2,
// ...
};
let result = foo(&object, 2.0);
}
The intent behind your approach is to only return a modified copy under certain conditions if I understand it right. In Rust this can be modeled with a function that returns an Option<~LargeStruct> type (perhaps even with Option<LargeStruct> but I'm not sure if the compiler can efficiently move large objects in this case).
fn foo(object: &LargeStruct, y: f32) -> Option<~LargeStruct> {
if object.x < y {
return Some(~LargeStruct {
x: y,
//n: object.n,
// ...
})
}
None
}
As for why your approach didn't work: Rust doesn't let you return a reference to an object that will be freed once the function returns. A lifetime is a way to say that an object must live at least as long as the references to it.
The answer to the question as asked
It is not possible to design something in this way with it completely transparent; a reference must always have a lifetime not in excess of the scope of its owner; it is thus impossible to return a reference to an object whose scope does not exceed the function.
This can be solved in a way with an enum specifying the return type as either a reference to a LargeStruct or a LargeStruct, but it's clumsy:
pub struct LargeStruct {
a: int,
}
pub enum LargeStructOrRef<'a> {
LargeStructRef(&'a LargeStruct),
LargeStruct(LargeStruct),
}
fn foo<'a>(object: &'a LargeStruct, y: f32) -> LargeStructOrRef<'a> {
if object.x < y {
LargeStruct(LargeStruct {
x: y,
n: object.n,
// ...
})
} else {
LargeStructRef(object)
}
}
You'd then need to do pattern matching between LargeStruct and LargeStructRef—it can't be made transparent to the caller.
Alternative designs
You can probably design this in a different way which will resolve these difficulties. For example, you might make foo take a &mut LargeStruct and modify the struct rather than creating a new one if object.x < y. (This is most likely to be the design you actually want, I think.)

Resources