After reading the rust book many times I think I'm starting to get the gist of lifetimes, but for me, an additional problem is the syntax we need to use to declare them. I find it is really counterintuitive.
I've simplified a silly code of mine onto this pair of structs (which one referencing the other).
#[derive(Debug, Default)]
pub struct TestStructA {
pub byte_1: u8,
pub byte_2: u8,
pub vector: Vec<u8>,
}
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
&TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
}
}
#[derive(Debug, Default)]
pub struct TestStructB<'a> {
pub test_array: &'a [u8],
pub t_a: &'a TestStructA,
}
If you copy and paste this isolated code onto a main.rs file and compile it, then you get the following error:
error: expected `while`, `for`, `loop` or `{` after a label
--> src/main.rs:10:59
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
| ^^^ expected `while`, `for`, `loop` or `{` after a label
error: labeled expression must be followed by `:`
--> src/main.rs:10:59
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: 'a vec![1, 2, 3] }
| ---^^^^^^^^^^^^^
| | |
| | help: add `:` after the label
| the label
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
If I don't annotate the vector parameter lifetime, I get the expected: "check your lifetimes boy" (which makes sense).
error[E0515]: cannot return reference to temporary value
--> src/main.rs:10:9
|
10 | &TestStructA { byte_1: 10, byte_2: 20, vector: vec![1, 2, 3] }
| ^-------------------------------------------------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
Of course, if I choose a more drastic solution as removing the "vector" attribute from my struct, as all other attributes are scalars, the code compiles. But I need my struct to have non-scalar data structures of some kind. I suspect I need some kind of lifetime labeling for my vector inside the Default initializer, but I'm not sure what
By the way, I think my TestStructB is also properly lifetime annotated, but maybe not. Does it look correct?
Finally, I got here because the compiler said I needed to declare a Default initializer for the referenced (&) version of my original struct. This original struct was already happily used in my program, but never referenced. Whenever I started using it in a &referenced fashion, it was Rust claiming it needs its Default initializer. The thing is I still somewhat think I've done something wrong when using my referenced Struct, and that there is a proper way to use &referenced (and lifetime annotated) Structs without Rust complaining about their (non existing) default initializer.
EDIT: #JohnKugelman is more than right, I've come onto this "aberration" after the typical newbie fight with rust compiler trying to overcome the mainly cryptic messages it yields.
My simplified original was this one:
#[derive(Debug, Default)]
pub struct TestStructA {
pub byte_1: u8,
pub byte_2: u8,
pub vector: Vec<u8>,
}
#[derive(Debug, Default)]
pub struct TestStructB<'a> {
pub test_array: &'a [u8],
pub t_a: &'a TestStructA,
}
With this code, the error I get is:
error[E0277]: the trait bound `&TestStructA: Default` is not satisfied
--> src/main.rs:11:5
|
11 | pub t_a: &'a TestStructA,
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `&TestStructA`
|
= help: the following implementations were found:
<TestStructA as Default>
= note: required by `std::default::Default::default`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
Apparently rustc misled me into thinking I need a &Struct Default initializer? Can't say...
Your unusual requirement arises because you're trying to implement Default for a structure TestStructB containing a reference. Most of the time, Default is used on types that have all owned values or can be empty in some way.
In order to implement Default for a reference &'a TestStructA, you would have to have some constant or leaked value of the type that the Default::default implementation can return a reference to — basically there needs to be an &'static TestStructA.
This is simple to do if the vector is empty because Vec::new() is a const fn, so we can construct a full compile-time-constant instance of TestStructA:
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
static VALUE: TestStructA = TestStructA {
byte_1: 10,
byte_2: 20,
vector: Vec::new()
};
&VALUE
}
}
If you want to have some data in the vector, then you would have to use a lazy-initialization mechanism like once_cell to be able to execute vec! to allocate the vector's contents, then return a reference to it.
use once_cell::sync::Lazy;
static DEFAULT_A: Lazy<TestStructA> = Lazy::new(|| {
TestStructA {byte_1: 10, byte_2: 20, vector: vec![1, 2, 3]}
});
impl<'a> Default for &'a TestStructA {
fn default() -> &'a TestStructA {
&DEFAULT_A
}
}
If you were to do this, I'd recommend also implementing Default for TestStructA, because it is strange to have Default for the reference but not the owned value.
impl Default for TestStructA {
fn default() -> TestStructA {
DEFAULT_A.clone()
}
}
(This only works if TestStructA also implements Clone, but it probably should. If it shouldn't, then instead put the struct literal inside the TestStructA::default method and have DEFAULT_A just be defined as Lazy::new(TestStructA::default).)
However, all these details are only necessary because
You're implementing Default for TestStructB,
which always contains a reference to a TestStructA.
You should consider whether TestStructB actually needs this reference in the default case — if t_a has type Option<&'a TestStructA>, for example, then it can just default to None. I don't have enough information to say whether this is appropriate for your application — make your own choice based on what the exact purpose of these structures is.
Related
I have a custom trait that I use as the element type in a slice:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: &'a [Box<dyn IConstraint>]
}
I would like to offer an add_constraint method that does a copy-on-write of the slice. Something like this:
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: Box<dyn IConstraint<TNodeState>>) {
let mut constraints: Vec<Box<dyn IConstraint<TNodeState>>> = Vec::new();
constraints.copy_from_slice(self.constraints);
constraints.push(constraint);
self.constraints = &constraints;
}
}
The problem is I get this error:
the trait bound Box<dyn IConstraint<TNodeState>>: std::marker::Copy is not satisfied
the trait std::marker::Copy is not implemented for Box<dyn IConstraint<TNodeState>>
Ok, so the Box<T> doesn't implement the Copy trait. Fair enough. But how do I address that? Ideally, I'd reuse the boxes or at least the constraints because they are immutable. But if I can't do that due to rust ownership rules, how can I implement the Copy trait on a box type? I've tried various ways and they all produce errors.
This attempt produces "Copy not allowed on types with destructors":
impl<TNodeState> Copy for Box<dyn IConstraint<TNodeState>> {
}
What about Clone? I can switch to constraints.clone_from_slice(self.constraints);, but then implementing the Clone trait on IConstraint produces a bunch of "IConstraint cannot be made into an object" errors.
Even if I could get box to be cloneable, then of course I get the anticipated borrow lifetime flaw from my add_constraint method:
borrowed value does not live long enough
So do I have to throw out my add_constraint function idea altogether and force the owner of my struct to manually copy it? Given my actual struct contains 3 fields, that gets tedious as the owner now has to deconstruct the fields into locals in order to drop the immutable borrow, allowing the original vector to be mutated:
fn add_remove_constraint() {
let mut scenario = Scenario::<&str, bool, 3_usize>::new(&["A", "B", "C"]);
let mut constraints: Vec<Box<dyn IConstraint<bool>>> = Vec::new();
constraints.push(Box::new(SelectionCountConstraint {
nodes: [1, 2],
min: 1,
max: 2,
}));
scenario = Scenario {
constraints: &constraints,
..scenario
};
assert_eq!(1, scenario.get_constraints().len());
let nodes = scenario.nodes;
let selection_state = scenario.selection_state;
constraints.pop();
scenario = Scenario {
constraints: &constraints,
nodes,
selection_state,
};
assert_eq!(0, scenario.get_constraints().len());
}
I think you got it all wrong. As said in the comments, your add_constraint will never work, because you are referencing something you create in the same function in the first place (which will be dropped after the function scope expires).
You should own a container over those IConstraint trait, but inside you should have an &dyn IConstraint or Box<dyn IConstraint>.
Adding an item to them is trivial in that case:
pub trait IConstraint {
// members here
}
pub struct Scenario<'a> {
pub constraints: Vec<&'a dyn IConstraint>
}
impl<'a> Scenario<'a> {
pub fn add_constraint(&mut self, constraint: &'a dyn IConstraint) {
self.constraints.push(constraint);
}
}
Playground
This should solve your problem since references are Copy.
This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 1 year ago.
I'm having a hard time resolving a lifetime issue:
pub struct A<'a> {
pub a: &'a str,
pub b: &'a u8,
}
pub enum Executable<'a> {
ExecutableA(A<'a>),
}
pub struct Config {
pub a: String,
pub b: u8, // some more config values to follow
}
impl Config {
pub fn new() -> Config {
// Implementation details omitted due to irrelevancy
unimplemented!();
}
}
pub struct Cli<'a> {
pub config: Config,
pub execution_list: Vec<Executable<'a>>,
}
impl<'a> Cli<'a> {
pub fn new() -> Cli<'a> {
Cli {
config: Config::new(),
execution_list: vec![],
}
}
pub fn prepare(&mut self) {
self.execution_list.push(
// Compilation error occurs for following line
Executable::ExecutableA(A {
a: &self.config.a,
b: &self.config.b,
}),
)
}
}
The compilation error is:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/lib.rs:39:20
|
39 | a: &self.config.a,
| ^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 35:20...
--> src/lib.rs:35:20
|
35 | pub fn prepare(&mut self) {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:39:20
|
39 | a: &self.config.a,
| ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 27:6...
--> src/lib.rs:27:6
|
27 | impl<'a> Cli<'a> {
| ^^
note: ...so that the expression is assignable
--> src/lib.rs:38:13
|
38 | / Executable::ExecutableA(A {
39 | | a: &self.config.a,
40 | | b: &self.config.b,
41 | | }),
| |______________^
= note: expected `Executable<'a>`
found `Executable<'_>`
(Playground)
After doing a lot of reading and looking at other questions, I still can't convince myself that I'm understanding the error correctly, mainly because I can't reason why the compiler is attaching the "anonymous" lifetime to the &mut self reference in the prepare function.
My general design idea is that I'll have my Cli struct contain a config, and a list of executables such that I can add all relevant executables to that list in the Cli's prepare function (where I'd like those executables to be able to reference values owned by the Config). I'll then iterate over that execution list to start/stop executables.
I think one answer to this question is to not have executables maintain references to config values and instead copy those values, but I feel like that shouldn't be necessary, and would like to use this issue as a learning opportunity.
I'm totally open to suggestions around "Maybe you should rethink your design and do X, instead."
Anonymous lifetimes are inferred by the compiler, most of them will point to 'static,
If you add this (&'a mut self):
pub fn prepare (&'a mut self) /* ... */
It compiles just fine, since the impl lifetime requirement is not conflicting with the Executable one.
Edit:
As pointed out, i was wrong (probably because the rust style did reach into my mind but lifetimes did not), i though about generic lifetimes but i looked at the already existing lifetime 'a and found that it compiled, at least mutably borrowing the class for eternity makes sense.
About your design:
I found it good for what you are trying to do, also i am not the expert with designs, specially in rust, so i found nothing wrong about it.
Viable solution:
Like pointed out, you could add the generic lifetime:
pub fn prepare <'b> (&'b mut self) { ... }
Now whenever the function is called the mutable borrow will last the needed lifetime, and when you want to immutably borrow it, it will work.
I'm trying to write a simple code which generates elements based on a random number generator, for which I have a working code here. Now I wanted to add a reference from each struct to the next in the list. The basic idea is that each struct has a state and an optional reference to another struct with the same lifetime.
#[derive(Copy, Clone, Debug)]
enum MyState
{
On,
Off
}
#[derive(Copy, Clone, Debug)]
struct MyStruct<'a>
{
state: MyState,
next_struct : Option<&'a MyStruct<'a>>,
}
The generic lifetime parameter 'a is a new addition to basically mark the fact that all structs have the same lifespan.
Then I have a simple associated function creating random structs with no reference, but now my impl block must also have the generic lifetime parameter.
// stand-in for replacement struct from rand crate
struct RandomGenerator {
random_number : f64,
}
impl<'a> MyStruct<'a>
{
fn random(r : & mut RandomGenerator) -> MyStruct
{
if r.random_number > 0.5 {
r.random_number -= 0.1;
return MyStruct{state : MyState::On, next_struct : None};
}
r.random_number = 1.0 as f64;
MyStruct{state : MyState::Off, next_struct : None}
}
}
Finally I'm trying to generate my elements in a loop
fn main() {
let mut grid = Vec::<MyStruct>::new();
let mut rng = RandomGenerator{random_number : 0.5};
for _i in 0..GRID_SIZE*GRID_SIZE // const GRID_SIZE : usize = 10;
{
grid.push(MyStruct::random(&mut rng));
}
println!("{:#?}", grid);
}
The full code is here. While the first version worked as expected, the second version fails to compile with
error[E0499]: cannot borrow `rng` as mutable more than once at a time
--> src/main.rs:43:60
|
43 | grid.get_mut(i).unwrap().push(MyStruct::random(&mut rng));
| ^^^^^^^^ `rng` was mutably borrowed here in the previous iteration of the loop
error: aborting due to previous error
Looking at similar questions most of them deal with self references, which seems to be more complicated than what I'm doing here, since I'm passing an unrelated object just for one function call, and it appears to be burrowed for longer..
I tried adding a generic lifetime 'b to the random method, which is then used only for the RNG mutable, but this does not work either. Why would adding a generic lifetime parameter that is not even used in the signature of the function changes the borrowing behaviour? What is the correct way to write this?
Here's a working version of your function (playground):
impl<'a> MyStruct<'a>
{
fn random(r: &mut RandomGenerator) -> MyStruct<'a>
{ // ^^^^
This is due to lifetime elision:
If there is exactly one input lifetime position (elided or not), that lifetime is assigned to all elided output lifetimes.
Since you didn't annotate the lifetime tied to MyStruct, the compiler inferred it must be linked to the lifetime of r.
I don't understand why the following doesn't work:
use std::collections::HashMap;
#[derive(Debug,Clone,PartialEq)]
struct Foo<'a> {
contents: HashMap<&'a str, Foo<'a>>,
}
fn bar<'a>(val: Foo<'a>) -> Foo<'a> {
*val.contents.get("bar").clone().unwrap()
}
error[E0507]: cannot move out of a shared reference
--> src/lib.rs:9:5
|
9 | *val.contents.get("bar").clone().unwrap()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Foo<'_>`, which does not implement the `Copy` trait
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8ab3c7355903fc34751d5bd5360bb71a
I'm performing a .clone(), which I thought should allow me to return the resulting value whose ownership should be disentangled from the input value, but that doesn't appear to be the case.
Another weird thing, which isn't a blocker on its own but may hint at the underlying problem, is that for some reason the .clone() returns a &Foo, which is surprising because in other cases I've mostly seen .clone() go from &T -> T. This is why the * is there; without it this doesn't pass type checking. I know Rust has some "magical" referencing/dereferencing rules, but I can't quite figure this one out.
HashMap.get returns an Option<&T>. Cloning this option gives you another Option<&T>, referencing the same object.
If you want to convert a Option<&T> to a new Option<T> where T supports Clone you can use .cloned(). There's also no need to dereference anymore as you have a T not an &T.
This means your code will look like this:
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
struct Foo<'a> {
contents: HashMap<&'a str, Foo<'a>>,
}
fn bar<'a>(val: Foo<'a>) -> Foo<'a> {
val.contents.get("bar").cloned().unwrap()
}
I have this simple snippet of code, which uses an arena for memory allocation and a trait CloneInto whose purpose is to clone a structure from unknown origins into an Arena, adjusting the lifetimes as it goes:
struct Arena;
impl Arena {
fn insert<'a, T: 'a>(&'a self, _: T) -> &'a mut T { unimplemented!() }
}
trait CloneInto<'a> {
type Output: 'a;
fn clone_into(&self, arena: &'a Arena) -> Self::Output;
}
It can be used as is:
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
struct Simple<'a> { a: &'a usize }
impl<'a, 'target> CloneInto<'target> for Simple<'a> {
type Output = Simple<'target>;
fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
Simple { a: arena.insert(*self.a) }
}
}
fn main() {
let arena = Arena;
let _ = Simple { a: &1 }.clone_into(&arena);
}
Or could, until the update to Rust 1.18. Now the compiler emits this error:
error[E0034]: multiple applicable items in scope
--> <anon>:25:30
|
25 | let _ = Simple { a: &1 }.clone_into(&arena);
| ^^^^^^^^^^ multiple `clone_into` found
|
note: candidate #1 is defined in an impl of the trait `CloneInto` for the type `Simple<'_>`
--> <anon>:18:5
|
18 | / fn clone_into(&self, arena: &'target Arena) -> Simple<'target> {
19 | | Simple { a: arena.insert(*self.a) }
20 | | }
| |_____^
= note: candidate #2 is defined in an impl of the trait `std::borrow::ToOwned` for the type `_`
even though I do not even import std or ToOwned!
This is an unfortunate effect of how method resolution works in Rust. Unlike other languages which feature overloading, in Rust the exact function to be called must be resolved unambiguously with no regard for its arguments.
In this specific case, Rust 1.18 brings a new nightly method called clone_into on the ToOwned trait, and the ToOwned trait is implemented unconditionally for all types implementing Clone and imported automatically (via the prelude).
The fact that this method cannot be called on stable has no bearing; the method is first considered for resolution, and an error will be emitted if it is actually used.
Note that even though irking, there are benefits to this method of resolution: it is often unclear to a human being which overload is selected when several appear to be available, or why the expected overload is NOT being selected. By erring on the side of explicitness, Rust makes it a no-brainer.
Unfortunately, in this case this results in Simple::clone_into() becoming ambiguous.
There is no way to opt out of the ToOwned implementation (not without giving up Clone and Copy), so instead one must switch to an unambiguous call to clone_into using Fully Qualified Syntax (FQS):
fn main() {
let arena = Arena;
let _ = CloneInto::clone_into(&Simple { a: &1 }, &arena);
}