struct A {
name:String,
}
impl A {
fn go(&self) {}
}
struct B<'a> {
name:String,
a:&'a A,
}
impl<'a> B<'a> {
fn go(&self) {
//do something different by self.name
self.a.go();
}
}
struct C<'a> {
a:A,
b1:B<'a>,
b2:B<'a>,
}
impl<'a> C<'a> {
fn b_go(&self, index:i32) {
if index == 1 {
self.b1.go();
}
else
{
self.b2.go();
}
}
fn a_go(&self) {
self.a.go();
}
}
fn factory<'a>() -> C<'a> {
let num = 5;
let a = A {
name:"a".to_string(),
};
let b1 = B {
name:"b1".to_string(),
a:&a,
};
let b2 = B {
name:"b2".to_string(),
a:&a,
};
let c = C {
a:a,
b1:b1,
b2:b2,
};
c
}
fn main() {
let c = factory();
}
What should I do?
Runnable, on the playpen: Rust Playground
It's always good to also check out the error message, it has helpful hints. In our case:
<anon>:54:12: 54:13 error: `a` does not live long enough
<anon>:54 a:&a,
^
<anon>:47:27: 66:2 note: reference must be valid for the lifetime 'a as defined on the block at 47:26...
<anon>:47 fn factory<'a>() -> C<'a> {
<anon>:48 let num = 5;
<anon>:49 let a = A {
<anon>:50 name:"a".to_string(),
<anon>:51 };
<anon>:52 let b1 = B {
...
<anon>:51:7: 66:2 note: ...but borrowed value is only valid for the block suffix following statement 1 at 51:6
<anon>:51 };
<anon>:52 let b1 = B {
<anon>:53 name:"b1".to_string(),
<anon>:54 a:&a,
<anon>:55 };
<anon>:56 let b2 = B {
...
The issue is, a
does not live long enough, because it must live as long as the <'a>
in your function signature, but only lives until the end of the function. In other words, Rust has detected a dangling pointer for you.
However, you want c
to own a
, while also owning b1
and b2
to have references to it. This kind of structure is hard for Rust: If we move a
, then b1
and b2
's references would need to be updated, but there's no way to do that. And this is what happens: you create a
, and then take two references to it, and then move a
into c
.
It's just a bit too early for me to hack out a solution here, hopefully someone else can give you more guidance on that, but that's your core problem. I'm not sure if you can make it work without using shared ownership.
Thank you.
I find a way. Using the Arc, but I don't know if it is right.
use std::sync::{Arc};
struct A {
name:String,
}
impl A {
fn go(&self) {
println!("from the {}.", self.name);
}
}
struct B {
name:String,
a:Arc<A>,
}
impl B {
fn go(&self) {
println!("from {}.", self.name);
//do something different by self.name
self.a.go();
}
}
struct C {
a:Arc<A>,
b1:B,
b2:B,
}
impl C {
fn b_go(&self, index:i32) {
if index == 1 {
self.b1.go();
}
else
{
self.b2.go();
}
}
fn a_go(&self) {
self.a.go();
}
}
fn factory() -> C {
let num = 5;
let a = A {
name:"a".to_string(),
};
let a_data = Arc::new(a);
let b1 = B {
name:"b1".to_string(),
a:a_data.clone(),
};
let b2 = B {
name:"b2".to_string(),
a:a_data.clone(),
};
let c = C {
a:a_data,
b1:b1,
b2:b2,
};
c
}
fn main() {
let c = factory();
c.b_go(1);
c.b_go(2);
c.a_go();
}
You can't move a struct while it's borrowed (the references would be invalidated). In your case, you're moving a
into c
while it's borrowed by b1
and b2
.
One solution is to use an Rc
to share a
between b1
, b2
, and c
equally. However, you would be better off finding a ownership hierarchy where every data structure has only one owner.
You don't need an Arc
because you will only ever reference an A
from one thread at a time. Rc
will give you better performance.
Thanks.
I have a problem with thread safe.
use std::thread;
use std::sync::{Arc, Mutex};
struct A {
name:String,
}
struct B {
a:A
}
impl A {
fn go(&self)
{
println!("a go....");
}
}
fn main() {
let a = A {
name:"a".to_string(),
};
let arc_b = Arc::new(B {a:a});
for i in 0..3 {
//increases the internal count
let arc_b = arc_b.clone();
thread::spawn(move || {
arc_b.a.go();
});
}
thread::sleep_ms(500);
}
Is that means i passed arc_b.a that isn't implement sync and send to another thread?
And if i mutex the shared data of arc_b.a, is that thread safe?
It's thread safe as is. You only need a mutex if you want to modify an object from multiple threads.