Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return a vector element from a Rust function?

I would like to return an element of a vector:

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)

I always get this error:

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>`

How do I return an element?

like image 515
plailopo Avatar asked Nov 23 '16 12:11

plailopo


People also ask

How to access vector elements using the get() function in rust?

The source code to access vector elements using the get () function is given below. The given program is compiled and executed successfully. // Rust program to access vector elements // using get () function fn value (n: Option <& char >) { match n { Some (n) => print! ( " {} " ,n), None => println!

How to return a vector from a function in C++?

This article will introduce how to return a vector from a function efficiently in C++. Use the vector<T> func() Notation to Return Vector From a Function. The return by value is the preferred method if we return a vector variable declared in the function. The efficiency of this method comes from its move-semantics.

Why can't I change the return value of a vector?

That means that the vector containing the values must outlive the return value, otherwise the reference would point to undefined memory. If you cannot change the vector, then you will need to make a copy of your data structure.

Is rust safe for arrays and vectors?

Arrays and vectors being one of the first few data structures that new programmers learn, it is no surprise that Rust too has a solid support for them. But as we saw, Rust's safety guarantees do not allow programmers to abuse these fundamental data types.


1 Answers

Look at the signature for Vec::first:

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

Given a reference to a vector, it will return a reference to the first item if there is one, and None otherwise. That means that the vector containing the values must outlive the return value, otherwise the reference would point to undefined memory.

There are two main avenues:

  1. If you cannot change the vector, then you will need to make a copy of your data structure. The easiest way to do this is to annotate the structure with #[derive(Clone)]. Then you can call Option::cloned on the result of first.

  2. If you can change the vector, then you can remove the first value from it and return it. There are many ways of doing this, but the shortest code-wise is to use the drain iterator.

#[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());
}

Additional changes:

  1. There's no need for TestVec if there's no state; just make functions.
  2. Rust style is snake_case for method and variable names.
  3. Use vec! to construct a vector when providing all the elements.
  4. Derive Debug so you can print the value.

If you wanted to always get the last element, you can use pop:

fn find_one_by_pop() -> Option<EntryOne> {
    find_all().pop()
}
like image 194
Shepmaster Avatar answered Oct 16 '22 08:10

Shepmaster