You have two options.
If you wish to use a borrowed pointer, you may write the function
`new()` like so:
static fn new(value: &lifetime/str) -> StringReader/&lifetime {
StringReader { data: value, next: 0 }
}
The notation StringReader/&lifetime is (probably) not well-documented.
What it means is: "a StringReader instance which contains borrowed
pointers with the lifetime `lifetime`". So basically it is specifying
the lifetime of the `value` field, in this case. Note that if the
`StringReader` had multiple borrowed pointers contained within, they
would all have to have the same lifetime.
Alternatively, you could have the StringReader own the data it is
reading from, in which case you would want to use an `@str` or `~str`,
just as you showed. Ultimately, we would probably want both types in
the standard library, since each can be useful in different circumstances.
Regarding your second question, the compiler makes some effort to
construct data precisely into the location where it is needed. So in
the constructor function above, what happens is that a pointer into the
caller's stack is passed as an implicit first parameter. The struct is
then written directly into the caller's stack. This works so long as
the return expression itself constructs the struct (more generally, so
long as you return an rvalue). It would not work if you stored the
struct into a variable and returned that.
e.g., although there is no semantic difference, this program would *not*
be optimized:
static fn new(value: &lifetime/str) -> StringReader/&lifetime {
let r = StringReader { data: value, next: 0 };
return r;
}
Here the compiler would produce a memcpy.
Niko
Colin Fleming wrote:
Hi all,
I'm playing around with Rust a little having been interested in it for
a while. I've read the language and borrowed pointers tutorials but
I'm still struggling with what seems like a fairly trivial example.
I have a StringReader type:
struct StringReader {
data: &str,
mut next: uint
}
and I'm trying to create a constructor for it:
impl StringReader {
static fn new(value: &str) -> StringReader {
StringReader { data: value, next: 0 }
}
}
I can't do this because the compiler "cannot infer an appropriate
lifetime", which I take to mean that it can't work out the lifetime of
'value', probably because I shouldn't be using a borrowed pointer here.
I tried a named lifetime, to indicate that the returned StringReader
pointer should be valid as long as the string is:
static fn new(value: &lifetime/str) -> &lifetime/StringReader {
&StringReader { data: value, next: 0 }
}
but that doesn't work either since the lifetime of the return value is
not the same as the lifetime of the param.
I also tried by value:
struct StringReader {
data: str,
mut next: uint
}
static fn new(value: str) -> StringReader {
StringReader { data: value, next: 0 }
}
but to my amazement "bare `str` is not a type" - I'd expected this
just to create an inefficient copying version.
The only thing I've managed to get to work is an owned string:
struct StringReader {
data: ~str,
mut next: uint
}
static fn new(value: ~str) -> StringReader {
StringReader { data: value, next: 0 }
}
Is this my best option here? What is the best practice for constructors?
Another thing that I don't quite understand: according to the
tutorials, a struct constructed so:
StringReader { data: value, next: 0 }
is allocated on the stack. How does this work with the return value of
the constructor? Since the return value is only in scope in the
constructor body, I suppose this means that the return value of the
constructor is copied - isn't this inefficient for constructors?
Thanks for any and all clarification,
Colin
_______________________________________________
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