Return the index of an element

I am still very much in the early learning phase of learning about programming languages. As far as Rust, I have covered basic control flow (if/else, for loops), primitive data types, functions, structs and impl but that's about it. I am not familiar with what a trait is or a closure and many other things....but I figured I'd ask this question before I confused myself further...

If I want to return the index of an element (of a vector in this case), what is the best way to do this using a for loop, similar to what I am trying to do here?

Example: I would like to return the index of an element in a vector given a target value 9, otherwise return -1

struct Solution;

impl Solution {
    fn search(nums: Vec<i32>, target: i32) -> i32 {
        for index in nums {
            if nums[index] == target 
			{
                return index
            }
        }
        -1
    }
}

fn main() {
    let nums = vec![-1, 0, 3, 5, 9, 12];
    let target = 9;
    let my_search = Solution::search(nums, target);
	println!("{}", my_search)
}

Error E0277 is what usually appears when trying to do this but it hasn't been the only error. It seems to be mostly about the vectors index type versus the type of the variable I am using but that's kind of a guess. :smiley: The fact that I haven't gotten to Traits yet is probably hindering some of my issues here. And there are other ways to do this I've noticed where you don't have to deal with this but I am more interested in how it's done with a for loop, similar to what I am trying to do here.

The code below is what I came up before I changed to the code above....this seemed to work but I think this way is not correct, right? And honestly, I sort of used the compilers hints to add the TryInto :smiley: ...I have NO IDEA what it does either so...

use std::convert::TryInto;

struct Solution;
impl Solution 
{
    fn search(nums: Vec<i32>, target: i32) -> i32 {
        for i in 0..nums.len(){
            if nums[i] == target.try_into().unwrap() 
			{
				return i.try_into().unwrap()
			}
        }
		-1
    }
}

fn main() {
    let nums = vec![-1, 0, 3, 5, 9, 12];
    let target = 9;
    let my_search = Solution::search(nums, target);
	println!("{}", my_search)
}


edit: I would like to add, please feel free to show other ways of doing this. I tried using position [Iterator in std::iter - Rust] but lack the knowledge of how to implement it.

for index in nums doesn't iterate over the indexes, it iterates over the elements of nums.

The second snippet is "correct", although not idiomatic. Exactly for the same reason why the try_into() annotation is needed when returning the index: vector indexes and sizes are of type usize, not i32. (The try_into in the comparison is completely unnecessary.)


I think it would be clearer if you didn't iterate over a vector of integers, but used a vector of strings instead, for example. That way you wouldn't stand a chance of confusing whether you are dealing with an index or with an actual element.

1 Like

Without changing your search function signature, position could be used like:

    fn search(nums: Vec<i32>, target: i32) -> i32 {
        nums.iter()
            .position(|&n| n == target) // -> Option<usize>
            .map(|i| i.try_into().unwrap()) // -> Option<i32>
            .unwrap_or(-1) // -> i32
    }

But it would be more idiomatic to return the Option<usize> directly. You probably also don't want to consume the vector, so instead it could borrow that as a slice, nums: &[i32].

3 Likes