简体   繁体   中英

"mismatched types expected unit type `()` found enum `Option<String>`" Error when trying to read the content of a file with Tauri

I was trying to use the file picker of tauri to read the contents of a file in Rust this way.

fn open_file() -> Option<String> {
    let dialog_open_file = tauri::api::dialog::FileDialogBuilder::new();
    dialog_open_file.pick_file(|path| {
    match path {
      Some(directory) => {
          let archivo = fs::read_to_string(directory);
          match archivo {
              Ok(content) => { return Some(content); },
              Err(error) => { return None; }
          }
      },
      None => { return None; }
    }
  });
}

The problem is that when I try to return Some(content) I get the error "mismatched types expected unit type () found enum Option<String> "

error[E0308]: mismatched types
  --> src/main.rs:25:43
   |
25 |                   Ok(content) => { return Some(content); },
   |                                           ^^^^^^^^^^^^^ expected `()`, found enum
   = note: expected unit type `()`
               found enum `Option<String>`


error[E0308]: mismatched types
  --> src/main.rs:18:19
   |
18 | fn open_file() -> Option<String> {
   |    ---------      ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
   |    |
   |    implicitly returns `()` as its body has no tail or `return` expression
   |
   = note:   expected enum `Option<String>`
           found unit type `()`

I have tried many ways but I can't return the Option out of the function "dialog_open_file" to make the function return something.

It looks like tauri has changed its API in this area. See https://docs.rs/tauri-api/0.7.6/tauri_api/dialog/index.html . Now the functions no longer accept a closure, but instead return a dialog::Response struct.

This means your code could be written as something like:

// This is tauri's internal error type too.
use anyhow::{Error, bail};

fn open_file_impl() -> Result<String, Error> {
    use tauri::api::dialog::Response;
    let result = tauri::api::dialog::select(None,None)?;
    
    let path = match {
        Response::Okay(s) => s;
        Response::OkayMultiple(s) => bail!("multiple selected"),
        Response::Cancel => bail!("canceled");
    }
    Ok(fs::read_to_string(directory)?)
}

pub fn open_file() -> Option<String> {
   open_file_impl().ok()
}

I'd probably introduce a concrete error type with this, rather than relying on anyhow ... but that does make things longer.

Or you could get rid of the open_file_impl altogether...

fn open_file_impl() -> Option<String> {
    use tauri::api::dialog::Response;

    let result = tauri::api::dialog::select(None,None).ok()?;
    if let Response::Okay(path) = result {
        fs::read_to_string(directory).ok()
    } else {
        None
    }
}

Edit

This post does not work for the OP question, because tauri's API requires the closure to be 'static , and thus rules out the possibility (except with dirty unsafe hacks) to retrieve the content of the file in a way similar to what was asked.

Also, tauri's API has been changed in more recent versions. If you are only interested in a solution that specifically works with tauri, please see @Michael Anderson's answer.


As you can see, there are two errors, which are opposite, in some way: one error tells you that Rust expected () , but found Option<String> , and the other one that it expected Option<String> , but found () . This should prompt you to check if you are passing you Option<String> at the right place and, in fact, you're not.

A closure is a function (not quite the same as other functions you define with fn , but still a function), so when you call return in it, you're actually returning inside the closure. So, the error just comes from the fact that pick_file expected a function that returns () , whereas you provided one that returns Option<String> , and conversely the outer function is (implicitly) returning () .

You may ask: is there a way to return from inside the closure, but for the return statement to apply to the outside function, and the answer is no , so one way would be to create a variable outside and mutate it from inside the closure:

fn open_file() -> Option<String> {
    let dialog_open_file = tauri::api::dialog::FileDialogBuilder::new();
    let mut result = None;
    dialog_open_file.pick_file(|path| {
        if let Some(directory) = path {
            let archivo = fs::read_to_string(directory);
            if let Ok(content) = archivo {
                result = Some(content);
            }
        }
    });
    result
}

If you format your code, you would find out that you are missing the return statement in the outer space.

fn open_file() -> Option<String> {
    let dialog_open_file = tauri::api::dialog::FileDialogBuilder::new();
    let mut result = None;
    dialog_open_file.pick_file(|path| match path {
        Some(directory) => {
            let archivo = fs::read_to_string(directory);
            match archivo {
                Ok(content) => result = Some(content),
                Err(error) => result = None,
            }
        }
    });
    result
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM