The borrow checker is correct, your code is not actually safe. Imagine this:
let mut info = build(String::from_str("this is a test"));
info.text = String::from_str("this assignment drops the original
string");
info.fields[0]; // Accesses freed memory.
The thing is that `Info.text` is not guaranteed to live as long as `Info`.
If you change the type of `Info.text` and the argument of `build` to `&'a
str` and pass "this is a test" everything works nicely. I suppose it would
be safe if you could convince the compiler that `Info.text` cannot change
but there is only inherited immutability so that does not work.
You could do something with arenas; by only having a borrowed reference to
`Info` the compiler should ensure that you do not sneakily change either
`Info.text` or 'Info.fields`.
----------------------------------------------------------------------
extern crate arena;
fn main() {
let ref ar = arena::Arena::new();
let info = build(ar, "this is a test");
println!("{}", info.fields[0]);
}
struct Info<'a> {
text: &'a String,
fields: Vec<&'a str>,
}
fn build<'a>(ar: &'a arena::Arena, text: &str) -> &'a Info<'a> {
ar.alloc(||{
let mut result = Info {
text: ar.alloc(||String::from_str(text)),
fields: vec![],
};
result.fields = result.text.as_slice().split(' ').collect();
result
})
}
----------------------------------------------------------------------
On Wed, Aug 13, 2014 at 7:45 AM, David Brown <[email protected]> wrote:
> I'm trying to figure out how to get something like this to compile.
> What I want is a struct that owns a string as well as contains
> structures containing slices of that string. My real use case is more
> complicated, but it seems to boil down easily to this.
>
> This gives me an error:
>
> life.rs:16:21: 16:32 error: `result.text` does not live long enough
> life.rs:16 result.fields = result.text.as_slice().split('
> ').collect();
> ^~~~~~~~~~~
> life.rs:13:40: 19:2 note: reference must be valid for the lifetime 'a as
> defined on the block at 13:39...
> life.rs:13 fn build<'a>(text: String) -> Info<'a> {
> life.rs:14 let mut result = Info { text: text, fields: Vec::new() };
> life.rs:15 life.rs:16 result.fields = result.text.as_slice().split('
> ').collect();
> life.rs:17 life.rs:18 result
> ...
> life.rs:13:40: 19:2 note: ...but borrowed value is only valid for the
> block at 13:39
> life.rs:13 fn build<'a>(text: String) -> Info<'a> {
> life.rs:14 let mut result = Info { text: text, fields: Vec::new() };
> life.rs:15 life.rs:16 result.fields = result.text.as_slice().split('
> ').collect();
> life.rs:17 life.rs:18 result
> ...
>
> Is there a way to do this, or do I need to allocate strings for the
> copies of the individual slices?
>
> Thanks,
> David Brown
>
> ----------------------------------------------------------------------
> // life.rs
>
> fn main() {
> let info = build(String::from_str("this is a test"));
> println!("{}", info.fields[0]);
> }
>
> struct Info<'a> {
> text: String,
> fields: Vec<&'a str>,
> }
>
> fn build<'a>(text: String) -> Info<'a> {
> let mut result = Info { text: text, fields: Vec::new() };
>
> result.fields = result.text.as_slice().split(' ').collect();
>
> result
> }
> ----------------------------------------------------------------------
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev