How to Fix Type Mismatch in a Function?

Here I use for_each and for to process, what are the differences between these two ways of processing? for_each passes a tuple, but I think this does not conflict with the type I return!

pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {

    let mut map = std::collections::HashMap::new();

    nums.iter().enumerate().for_each(|(i, k)| {
        if let Some(&a) = map.get(&(target - k)) {
            return vec![a, i.try_into().unwrap()];
        }
        map.insert(k, i);
    });

    // Pass the test
    // for (i, k) in nums.iter().enumerate() {
    //     if let Some(&a) = map.get(&(target - k)) {
    //         return vec![a, i.try_into().unwrap()];
    //     }
    //     map.insert(k, i.try_into().unwrap());
    // }

    vec![]
}

#[test]
fn test_two_sum_v1() {
    assert_eq!(two_sum(vec![2, 7, 11, 15], 9), vec![0, 1]);
    assert_eq!(two_sum(vec![3, 2, 4], 6), vec![1, 2]);
    assert_eq!(two_sum(vec![3, 3], 6), vec![0, 1]);
}


This produces the following error:

// error[E0308]: mismatched types
//  --> src/lib.rs:7:20
//   |
// 7 |             return vec![a, i.try_into().unwrap()];
//   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Vec<_>`
//   |
//   = note: expected unit type `()`
//                 found struct `Vec<_>`
// note: return type inferred to be `()` here
//  --> src/lib.rs:7:20
//   |
// 7 |             return vec![a, i.try_into().unwrap()];
//   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)

When you use for_each, you are passing a closure. The return statement is returning from that closure, not the surrounding function. Also, for_each expects the closure to return () -- that is, it expects it to return nothing.

Edit: and no, there is no way to get a closure to return from an outer function.

Honestly, you should just use for rather than for_each here. Otherwise, you'll probably have to mess with some combination of try_fold and ControlFlow, and I can't see it being worth it. I mean, unless you want to figure out how to do it. :slight_smile:

4 Likes

Decided to work it out for myself.

pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    use std::ops::ControlFlow;

    let mut map = std::collections::HashMap::new();

    let r = nums.iter()
        .enumerate()
        .try_for_each(|(i, &k)| {
            let i: i32 = i.try_into().unwrap();
            if let Some(&a) = map.get(&(target - k)) {
                return ControlFlow::Break(vec![a, i]);
            }
            map.insert(k, i);
            ControlFlow::Continue(())
        });
        
    match r {
        ControlFlow::Break(v) => return v,
        ControlFlow::Continue(()) => vec![]
    }
}

#[test]
fn test_two_sum_v1() {
    assert_eq!(two_sum(vec![2, 7, 11, 15], 9), vec![0, 1]);
    assert_eq!(two_sum(vec![3, 2, 4], 6), vec![1, 2]);
    assert_eq!(two_sum(vec![3, 3], 6), vec![0, 1]);
}

Like I said, just use for. :slight_smile:

1 Like

The ControlFlowtry_fold group is something I didn't expect, and it's true that using for is the simplest way.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.