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 <dav...@davidb.org> 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
> Rust-dev@mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to