Vec与String一样,没有实现Copy特性((String默认是值传递,不是引用传递,也不是值复制):)
Vector(以及其他的集合)是值得讨论的,因为涉及到很多语义--容器本身,元素,以及迭代器。
我们在这里使用Vec作为例子,因为它是一个非常常见的数据结构的集合。其他也没有实现Copy特性的集合包括HashMap和HashSet。另一方面,数组的移动语义与结构类似,它们取决于项目的类型--但这是另一个问题。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; do_something(names); }
fn do_something(names: Vec<String>) { println!("{:?}", names); }
|
输出:
但是,当我们在do_something后面添加println! 语句。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; do_something(names); println!("{:?}", names); }
fn do_something(names: Vec<String>) { println!("{:?}", names); }
|
我们以前见过这种编译器错误,对于String类型,我们试图借用/使用一个已经被移动过的值:
error[E0382]: borrow of moved value: `names` --> src/main.rs:7:22
|
我们可以先借用names,这样我们就可以在事后把它移到do_something函数中,两行代码互换一下
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; println!("{:?}", names); do_something(names); }
fn do_something(names: Vec<String>) { println!("{:?}", names); }
|
输出:
["John", "Jane"] ["John", "Jane"]
|
我们可以重新设计do_something来借用names,这样我们就可以在println时再次借用它!。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; do_something(&names); println!("{:?}", names); }
fn do_something(names: &[String]) { println!("{:?}", names); }
|
下面的代码在我知道的编程语言中非常好,但是在这里,我们得到一个编译器错误:
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let name: String = names[0]; println!("Hello, {}", name); }
|
报错:
error[E0507]: cannot move out of index of `Vec<String>` --> src/main.rs:6:24
|
,如果你只从Vec中移出一个元素,你就会让向量处于无效状态--向量不再是一个同质元素的集合了
隐含地移出一个Vec是不允许的,因为这将使向量处于无效状态--一个元素被移出,其他元素没有一致性了:
如果我对这个向量进行迭代,我可能会访问一个无效的内存(被移出的元素)。
那么我们该怎么做呢?
我们可以通过使用索引操作符借用我们想要的值。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let name: &str = &names[0]; println!("Hello, {}", name); }
|
我们也可以使用.get方法借用该值。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let name: &str = names.get(0).unwrap(); println!("Hello, {}", name); }
|
我们可以用.first()或.last()方法借用这个值(当然,如果你想要第一项和最后一项)。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let name: &str = names.first().unwrap(); println!("Hello, {}", name); }
|
但是......如果我想拥有一个元素呢?
我们使用.into_iter()方法来拥有各个元素。在这里,我们在调用.next()后设法拥有了第一个元素。
fn main() { let names = vec![ String::from("John"), String::from("Jane"), ]; let mut names_iter = names.into_iter(); let name: String = names_iter.next().unwrap(); println!("Hello, {}", name); }
|
如果你想拥有第一个元素,这个例子是有效的。我想,如果你想拥有索引为n的元素(出于某种原因),你可以调用.skip(n)然后调用.next()。
对于Vec,我们可以.pop()最后一个元素并拥有数据(当然,只有当你想要一个向量的最后一个元素的时候)。
fn main() { let mut names = vec![ String::from("John"), String::from("Jane"), ]; let name: String = names.pop() .unwrap(); println!("Hello, {}", name); }
|