I think we should try to clear some definitions about lifetime. IMO, a
lifetime is a compile-time constant bound to some run-time variable. While
constructing one variable and its lifetime, we can deduce a lifetime from
variables within the same stack frame, or do some intersection operations
over lifetimes of other variables.
Based on the new popular syntax, we have some shorthand:
- *'x means lifetime of x
*
- *'x.fieldA.subFieldB* means lifetime of x.fieldA.subfieldB
- *'x ^ 'y* means intersection of lifetimes binding x and y
- *['x.*]* means lifetime vector of x's deep fields, this sigil is only
for easy description.
For Snippet "*x: &'a B<uint, 'c, 'd, 'e> = y*", we mean a borrowed box
*x *ref to
a resource *y* of type *B<uint>*, with *'x* == *'y ^* {all lifetimes tagged
with *'a*} and *['x.*] *==* ['c, 'd, 'e]*. IMO, the token *'a* here may
introduce some confusion, it allocates a new lifetime constant equals some
others' intersection, instead of simply fetching an existing one from a
variable. So how about trying to avoid "named lifetime", and explicitly
define the lifetime with intersect operations, for example:
- *x: &T<uint> ^ 'y ^ 'z = t*, or
- *x: &T<uint> ~ 'y ^ 'z = t*, or
- *x: &<T<uint> , 'y ^ 'z> = t
*
means a borrowed box *x *ref to a resource *t* of type T*<uint>*, with *'x*
== *'t ^ 'y ^ 'z*.
*
*
Then we can declare a function like this (part of assigning *['returnVal.*]* is
somewhat ugly):
- *fn foo(x: &X, y: &Y) -> T<uint, {fieldA: 'x ^ 'y, fieldB: {subFieldC:
'x ^ 'y}}> { ... }*
If *T<>* has many fields need to bind lifetimes on return type, we can give
a default one when defining *T<>*:
*
*
*struct T<U> {*
* fieldA: &str,*
* fieldB: &str ~ 'fieldA, // *default activity: 'fieldB = 'fieldA, else
use the one in <{fieldB: ...}>
* fieldC: [&str * 3] ~ 'fieldA,* // bind 'fieldC and we have 'fieldC[0]
== 'fieldC[1] == 'fieldC[2]
* fieldD: [&U * 3] ~ 'fieldA* // we have ['fieldC[0].*] ==
['fieldC[1].*] == ['fieldC[2].*]
*}*
*
*
then define *fn foo* and *fn each* as:
- *fn foo(x: &T<U>) -> T<uint, {fieldA: 'x, fieldD: 'x, *fieldD:
{subField: 'x }}> {*
- *pure fn each(&self, f: fn(&(&K ~ 'self, &V ~ 'self)) -> bool) {*
Here is StringReader example from Niko's blog without named lifetime:
struct StringReader {
value: &str,
count: uint
}
impl StringReader {
fn new(value: &str) -> StringReader <{value: 'value}> {
StringReader { value: value, count: 0 }
}
}
fn remaining(s: &StringReader) -> uint {
return s.value.len() - s.count;
}
fn value(s: &StringReader) -> &str ~ 's.value {
return s.value;
}
--
James Gao
On Thu, Jan 24, 2013 at 8:37 PM, Samuel de Framond <[email protected]>wrote:
> Just a stupid question, could we read this (assuming this syntax):
>
> &'a B<'c, 'd, 'e>
>
> as:
>
> A borrowed pointer of lifetime 'a to a value of type B with the lifetime
> parameters 'c, 'd, 'e.
>
> This must be obvious to many but I admit being quite new to this kind of
> lifetime parameter concept.
>
> Thanks!
>
> --
> Samuel de Framond
> P: +86 135 8556 8964
> M: [email protected]
>
>
> _______________________________________________
> 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