2016-11-23 138 views
3

我想回到一个向量的元素:如何从Rust函数返回一个向量元素?

struct EntryOne { 
    pub name: String, 
    pub value: Option<String>, 
} 

struct TestVec {} 

impl TestVec { 
    pub fn new() -> TestVec { 
     TestVec {} 
    } 

    pub fn findAll(&self) -> Vec<EntryOne> { 
     let mut ret = Vec::new(); 
     ret.push(EntryOne { 
      name: "foo".to_string(), 
      value: Some("FooVal".to_string()), 
     }); 
     ret.push(EntryOne { 
      name: "foo2".to_string(), 
      value: Some("FooVal2".to_string()), 
     }); 
     ret.push(EntryOne { 
      name: "foo3".to_string(), 
      value: None, 
     }); 
     ret.push(EntryOne { 
      name: "foo4".to_string(), 
      value: Some("FooVal4".to_string()), 
     }); 

     ret 
    } 

    pub fn findOne(&self) -> Option<EntryOne> { 
     let mut list = &self.findAll(); 

     if list.len() > 0 { 
      println!("{} elements found", list.len()); 
      list.first() 
     } else { 
      None 
     } 
    } 
} 

fn main() { 
    let test = TestVec::new(); 
    test.findAll(); 
    test.findOne(); 
} 

playground

我总是得到这样的错误:

error[E0308]: mismatched types 
    --> src/main.rs:40:13 
    | 
35 |  pub fn findOne(&self) -> Option<EntryOne> { 
    |        ---------------- expected `std::option::Option<EntryOne>` because of return type 
... 
40 |    list.first() 
    |    ^^^^^^^^^^^^ expected struct `EntryOne`, found &EntryOne 
    | 
    = note: expected type `std::option::Option<EntryOne>` 
       found type `std::option::Option<&EntryOne>` 

如何返回一个元素?

+1

你懂的值和值的参考值之间的差异? –

+0

@MatthieuM。好的,但我该如何按价值返回元素?我可以克隆/复制它吗? – plailopo

+0

@Shepmaster我已经尝试过,但没有工作 'pub fn findOne(&self) - > Option {self.findAll()。first()。cloned()}' 找不到名为'clone的'方法 – plailopo

回答

7

看那签名Vec::first

fn first(&self) -> Option<&T> 

给一个向量的引用,将返回引用的第一个项目,如果有一个,和None否则。这意味着包含值的向量必须超过返回值,否则引用将指向未定义的内存。

主要有两种途径:

  1. 如果你不能改变的载体,那么你需要让你的数据结构的副本。最简单的方法是用#[derive(Clone)]注释结构。然后您可以拨打Option::clonedfirst的结果。

  2. 如果您可以更改矢量,那么您可以从中删除第一个值并将其返回。有很多方法可以做到这一点,但最简单的代码是使用drain迭代器。

#[derive(Debug, Clone)] 
struct EntryOne { 
    name: String, 
    value: Option<String>, 
} 

fn find_all() -> Vec<EntryOne> { 
    vec![ 
     EntryOne { 
      name: "foo".to_string(), 
      value: Some("FooVal".to_string()), 
     }, 
     EntryOne { 
      name: "foo2".to_string(), 
      value: Some("FooVal2".to_string()), 
     }, 
     EntryOne { 
      name: "foo3".to_string(), 
      value: None, 
     }, 
     EntryOne { 
      name: "foo4".to_string(), 
      value: Some("FooVal4".to_string()), 
     }, 
    ] 
} 

fn find_one_by_clone() -> Option<EntryOne> { 
    find_all().first().cloned() 
} 

fn find_one_by_drain() -> Option<EntryOne> { 
    let mut all = find_all(); 
    let mut i = all.drain(0..1); 
    i.next() 
} 

fn main() { 
    println!("{:?}", find_one_by_clone()); 
    println!("{:?}", find_one_by_drain()); 
} 

其他变化:

  1. 没有必要为TestVec如果没有状态;只是做功能。
  2. 方式和变量名称的锈风格是snake_case
  3. 使用vec!在提供所有元素时构造向量。
  4. 导出Debug因此您可以打印该值。

如果你想始终获得最后元素,你可以使用pop

fn find_one_by_pop() -> Option<EntryOne> { 
    find_all().pop() 
}