variablesrusttypes

How to determine variable type in Rust to pass to function


I am trying to use the fuzzy-search crate to build a data structure of choices that I can efficiently query with one string at a time. I have successfully created the struct:

use fuzzy_search::{distance::levenshtein, symspell::SymSpell};
let mut matcher = SymSpell::new(levenshtein, 2);

for ns in all_name_strings {
    matcher.insert(ns);
}

Now I want to pass this variable to another function to do the actual querying, but I can't figure out which type to use in the definition. I've simplified the question by using the unit type shortcut here. The closest I've gotten is:

let (): SymSpell<fn(&str, &str) -> usize> = matcher;

But this still fails with:

 4  error[E0308]: mismatched types
    --> rust/shp_sanity/src/ed_builder.rs:278:53
     |
 278 |         let (): SymSpell<fn(&str, &str) -> usize> = matcher;
     |                 ---------------------------------   ^^^^^^^ expected `SymSpell<fn(&str, &str) -> usize>`, found `SymSpell<fn(..., ...) -> ... {levenshtein}>`
     |                 |
     |                 expected due to this
     |
     = note: expected struct `SymSpell<for<'a, 'b> fn(&'a _, &'b _) -> _>`
                found struct `SymSpell<for<'a, 'b> fn(&'a _, &'b _) -> _ {levenshtein}>`

I've tried putting {levenshtein} on the end, but unfortunately, that errors too. I initially thought I just needed to pass the function, e.g. SymSpell<levenshtein>, but that fails with:

 1  error[E0747]: constant provided when a type was expected
    --> rust/shp_sanity/src/ed_builder.rs:279:26
     |
 279 |         let (): SymSpell<levenshtein> = matcher;
     |                          ^^^^^^^^^^^
     |
     = help: `levenshtein` is a function item, not a type
     = help: function item types cannot be named directly

Ideally this crate would export a type that I could use, but I don't see one in this case.

How can I figure out the correct type to declare in my function?


Solution

  • The crate's owner made a mistake, as he (needlessly) restricted the E type directly in the struct definition, forcing users to pass the same bound here and there.

    pub struct SymSpell<E: Fn(&str, &str) -> usize> { .. }
    

    If you want to use the matcher inside, you need to define the same bounds anyway (playground):

    fn do_it<E: Fn(&str, &str) -> usize>(matcher: SymSpell<E>) {
        println!("yeah!");
    }
    
    fn do_it_with(matcher: SymSpell<impl Fn(&str, &str) -> usize>) {
        println!("yeah!");
    }