Unwrap() works, ? does not

[dependencies]
easy_process = "0.2.1"

https://crates.io/crates/easy_process

fn main() {

    let output = easy_process::run(r#"powershell /C 'echo "1 2 3 4"'"#).unwrap()/* ? */;
    assert_eq!(&output.stdout, "1 2 3 4\r\n");

}

What is wrong?
rustc 1.63.0 (4b91a6ea7 2022-08-08) on Win11

easy_process>cargo build
Blocking waiting for file lock on build directory
Compiling easy_process v0.1.0 (\easy_process)
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> src\main.rs:4:87
  |
1 | / fn main() {
2 | |     println!("Hello, world!\n"); 
3 | |
4 | |     let output = easy_process::run(r#"powershell /C 'echo "1 2 3 4"'"#)/* .unwrap() */?;
  | |                                                                                       ^ cannot use the `?` operator in a function that returns `()`
7 | |     println!("\nGoodbye, world!"); 
8 | | }
  | |_- this function should return `Result` or `Option` to accept `?` 
  | 
  = help: the trait `FromResidual<Result<Infallible, easy_process::Error>>` is not implemented for `()` 
For more information about this error, try `rustc --explain E0277`. 
error: could not compile `easy_process` due to previous error

The same situation with the crate
https://crates.io/crates/process_control

[dependencies]
process_control = "4.0"

fn main() {

use std::io;
use std::process::Command;
use std::process::Stdio;
use std::time::Duration;

use process_control::ChildExt;
use process_control::Control;

let process = Command::new("echo")
    .arg("hello")
    .stdout(Stdio::piped())
    .spawn()
    /* .unwrap() */?;

let output = process
    .controlled_with_output()
    .time_limit(Duration::from_secs(1))
    .terminate_for_timeout()
    .wait()?
    /* .unwrap() */
    .ok_or_else(|| {
        io::Error::new(io::ErrorKind::TimedOut, "Process timed out")
    })/* .unwrap() */?;
assert_eq!(b"hello", &output.stdout[..5]);

}

and with
https://crates.io/crates/process_list

[dependencies]
process_list = "0.2.1"
env_logger = "0.9.0"

// use process_list::for_each_module;
// use std::process;

fn print_stuff() {
    env_logger::init();
    process_list::for_each_module(std::process::id(), |(address, size), name| {
        println!("{:016X} - {} \t {}", address, size, name.display())
    }) // !!!!!!!!! ?
    .unwrap();
}


fn main() {

    fn print_processes(id : u32, name : &std::path::Path) {
        // println!("Id: {} --- Name: {}", id, name.display());
        println!("{}\t{}", id, name.display());
    }
    
    process_list::for_each_process(print_processes).unwrap(); // !!!! ?

    print_stuff();

}

Please read the corresponding documentation. It is explicitly spelled out that ? can only be used in functions that return fallible types (e.g. Result or Option).

4 Likes

Thank You for rresponse.
But, I this code copied from crate.io. It is not my thoughtfulness

In any case, the code is incorrect.

1 Like

Ok, thank you, again. Now I understand the situation.

You will find the code in the package documentation is supposed to be wrapped in a function that returns Result (often hidden in the documentation for brevity). For example, this in the source code for easy_process.

It should be understood that when a ? is used in an example, the enclosing function is expected to return Result.

2 Likes

For fn main I find it best to use the anyhow crate.. This allows you to just put ? after all your call types even though they have completely different Result error types.

  use anyhow::{Result,Context};

  fn main() -> Result<()> {
      let file = File::open(..)?;
      ...
      let map = ...;
      let value = map.get(key)
                                 .context("missing required key")?; // convert Option to Result with nice error message
     ...
     Ok(())
}

Don't do this in library calls because it obscures the Result types.. But for nobody-calls-me-but-my-own-main, this saves a LOT of hastle, and is MUCh better than just calling .unwrap() everywhere. It'll even encourage you to start returning nicer Result error messages as you get the hang of it.

2 Likes