[rust-dev] Converting ~[T] embedded in struct to &[T]

Alex Crichton alex at crichton.co
Sat Jan 18 23:01:57 PST 2014


>     fn borrow1<'a>(&'a self) -> &'a int {
>         match (self) {
>             // error: mismatched types: expected `&'a int` but found `~int`
>             // (expected &-ptr but found ~-ptr)
>             &Foo(ref v) => *v
>         }
>     }

This doesn't work because the local variable v has type &~int, when
you dereference this you get something of type ~int which if you load
is a move so you're not allowed to do that. Additionally, the return
type wants &int when you're giving it ~int

>     fn borrow2<'a>(&'a self) -> &'a int {
>         match (self) {
>             // WORKS
>             &Foo(ref v) => &**v
>         }
>     }

This works because you're going from &~int => ~int => int => &int via
the * => * => & ordering

>     fn borrow3<'a>(&'a self) -> &'a int {
>         match (self) {
>             // WORKS
>             &Foo(ref v) => do_borrow(*v)
>         }
>     }
> }

The reason this works and borrow1 doesn't is a little tricky. As I
said above, the intermediate value has type ~int. The function
do_borrow takes something of type &int, so the compiler will coerce
the value of type ~int. The compiler silently does this so you don't
have to. This is equivalent to writing (as in this is what the
compiler automatically injects)

    do_borrow(&**v)


> impl FooVec {
>     fn borrow1<'a>(&'a self) -> &'a [int] {
>         match (self) {
>             // error: mismatched types: expected `&'a [int]` but found
>             // `~[int]` ([] storage differs: expected &'a  but found ~)
>             &FooVec(ref v) => *v
>         }
>     }

This doesn't work due to the same reasons as the above borrow1

>
>     fn borrow2<'a>(&'a self) -> &'a [int] {
>         match (self) {
>             // error: type ~[int] cannot be dereferenced
>             &FooVec(ref v) => &**v
>         }
>     }

There's a subtle reason that this doesn't work. You'll note in the
above borrow2 I mentioned that you transformed ~int => int => &int. If
the same thing were to happen here, it would look like ~[int] => [int]
=> &[int]. This kind of promotion is not allowed yet (namely
dereferencing something of type ~[T]), but it will hopefully be
enabled soon with something called dynamically sized types (DST).

>     fn borrow3<'a>(&'a self) -> &'a [int] {
>         match (self) {
>             // error: mismatched types: expected `&'a [int]` but found
>             // `&<V2>` (expected vector but found &-ptr)
>             &FooVec(ref v) => do_borrow(*v)
>         }
>     }
> }

This doesn't work because the do_borrow function takes something of
type &int, not ~[int] (which is the type of *v). You'd need to rewrite
the borrow function to take &[int] instead of &int.

Another solution for vectors is to return v.as_slice() which is a
function that will convert all forms of vectors to its slice
representation (&[T])

Hope that helps!


More information about the Rust-dev mailing list