Denis (cc'ing rust-dev)-
> How does it then interpret the line:
> let it = self.items[0];
> The only way to make sense of that is to copy, isn't it? What else?
An assignment expression can denote either a copy or a *move* of the
right-hand-side into the left-hand-side.
Note that your goal ("returning an item from a collection") is unclear, in that
I cannot tell whether you want to move item out of the collection, or make a
copy of it, or provide a shared reference to the item in the collection (but
without removing it from the collection).
Anyway, the error message says "cannot move out of dereference of & pointer"
In this case, the assignment expression is being interpreted as an attempt to
move content out of self.items[0]. But you cannot move the item out of the
l-value denoted
by that expression, for a couple different reasons (such as: `&self` is an
immutable borrow, so you cannot modify it; and also, even if you changed the
borrow to be a mutable borrow, you still could not use the expression you want
to extract the first item, since the vector needs something to replace the
content that was removed).
Maybe you are more used to languages like Java/Scheme/ML/Haskell/etc, where a
parameter or local variable denotes a *reference* to the value in question, and
thus can be freely copied? To get that effect in Rust, and thus allow multiple
references to some shared piece of state, you need to use some explicit
pointer/reference type.
Here is some code to illustrate what I'm saying. Note that you should probably
favor a data-structure representation where you can call the vec `pop()` method
rather than `shift()`; compare the source code for each in vec.rs to see why.
```rust
struct Coll<Item> {
items : ~[Item]
}
impl<Item> Coll<Item> {
// *Moves* the first element out of self.
// (Doing so requires that we mutably-borrow self.)
fn first (&mut self) -> Item {
// ^^^ this is new
let it = self.items.shift();
// ^^^^^ so is this
return it;
}
// Provides reference to first element of self.
fn first_ref<'a> (&'a self) -> &'a Item {
// Note: The lifetime 'a tells us that the reference will
// survive only as long as the immutable-borrow of self.
let it = &'a self.items[0];
return it;
}
}
fn main () {
let mut coll = Coll{items:~[1,2,3]};
// ^^^ this is also new.
{
// This {} block acts effectively as the lifetime 'a for the
// call to first_ref.
// First lets take a reference, `fref`, into coll...
let fref = coll.first_ref();
println!("first ref : {:?}", fref);
println!("coll : {:?}", coll);
// ... which will only live until here...
}
// ... which is important, because we need to *mutably*
// borrow `coll` in order to invoke `first()` here.
println!("first : {:?}", coll.first());
println!("coll : {:?}", coll);
}
```
Cheers,
-Felix
----- Original Message -----
From: "spir" <[email protected]>
To: "Rust-dev" <[email protected]>
Sent: Monday, November 11, 2013 1:44:04 PM
Subject: [rust-dev] returning an item from a collection
Hello,
I am searching for the easy or standard way to return an item from a
collection.
Here is a fictional example showing the issue:
struct Coll<Item> {
items : ~[Item]
}
impl<Item> Coll<Item> {
fn first (&self) -> Item {
// this line is for comments below:
let it = self.items[0]; // error
return it;
}
}
fn main () {
let coll = Coll{items:~[1,2,3]};
println!("first : {:?}", coll.first());
}
==>
_.rs:12:18: 12:30 error: cannot move out of dereference of & pointer
_.rs:12 let it = self.items[0];
I could not find any clue in docs. Have tried several approaches, finally
succeeded with the following:
impl<Item:Clone> Coll<Item> {
fn first (&self) -> Item {
let it = self.items[0].clone();
return it;
}
}
I find that surprising. A few questions:
* What does the error *mean* ?
* Is this solution the right way?
* What alternatives exist, if any?
* What is the difference between copy and clone?
* Why does clone work and not simple copy?
About the latter 2 questions, well, for me,
y = x
just copies x into y [1]; and clone is just a synonym of copy. Where am I
wrong?
That we copy should remove any pointer safety question, shouldn't it? (This
consideration was my lead to find a solution.) Again, where am I wrong?
The doc of the module 'clone' reads:
<< The Clone trait for types that cannot be "implicitly copied"
In Rust, some simple types are "implicitly copyable" and when you assign them
or
pass them as arguments, the receiver will get a copy, leaving the original
value
in place. These types do not require allocation to copy and do not have
finalizers (i.e. they do not contain owned boxes or implement Drop), so the
compiler considers them cheap and safe to copy. For other types copies must be
made explicitly, by convention implementing the Clone trait and calling the
clone method. >>
This is all good and makes sense for me. But then, in the first code example
above, the compiler does not know anything about the "copy-ability" of Val
specimens. How does it then interpret the line:
let it = self.items[0];
The only way to make sense of that is to copy, isn't it? What else? Then, the
language should require Val to declare the trait Clone, shouldn't it? And there
should not be a need for an explicit copy via the clone method in my view...
Again, what other sense but copying does the compiler assign to a simple
assignment "y=x" ?
Finally, is it so that for generic collections, item types must always be
declared the Clone trait, else we just cannot read them? Same for generic
struct
fields? (If I add a field of type Item in Coll, I also cannot read it out
without error.)
Denis
[1] shallow copy: the pointer, if x is a pointer, the "façade" struct is x is
such an thing, etc...
_______________________________________________
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