Some use of error handling

I am a beginner who has just started learning Rust language for two months. If the question I'm asking seems a bit foolish, please don't mock me.
I am using the tokio-modbus library to implement Modbus TCP。
When I call the tcp:: connect method to asynchronously connect to the specified address socketaddr. Store the returned connection object in the ctx variable. I can use unwarp() like this:

let mut ctx = tcp::connect(socket_addr).await.unwrap();

But if I use ?, it will give an error like this:

let mut ctx = tcp::connect(socket_addr).await?;

The error is as follows:

the ? operator can only be used in an async block that returns Result or Option (or another type that implements FromResidual) the trait FromResidual<Result<Infallible, std::io::Error>> is not implemented for ()

This is the code for my entire function:

async fn client_context(socket_addr: SocketAddr) {
tokio::join!{
async {
// Give the server some time for starting up
tokio::time::sleep(Duration::from_secs(1)).await;// 等待1秒,确保服务器启动完成
println!("CLIENT: Connecting client...");
// 建立连接
// 通过调用tcp::connect方法异步地连接到指定地址'socket_addr'。将返回的连接对象存储在ctx变量中
let mut ctx = tcp::connect(socket_addr).await?;
println!("CLIENT: Reading 2 input registers...");
// 读取输入寄存器
// 从服务器读取起始地址为0x00的2个输入寄存器
let response = ctx.read_input_registers(0x00, 2).await.unwrap();
println!("CLIENT: The result is '{response:?}'");
assert_eq!(response.unwrap(), vec![1234, 5678]);
println!("CLIENT: Writing 2 holding registers...");
// 写入寄存器
// 从起始地址为'0x01'写入[7777,8888]两个数据
ctx.write_multiple_registers(0x01, &[7777, 8888]).await;
// Read back a block including the two registers we wrote.
println!("CLIENT: Reading 4 holding registers...");
// 读取保持寄存器
// 从服务器读取起始地址为0x01的4个保持寄存器
let response = ctx.read_holding_registers(0x00, 4).await.unwrap();
println!("CLIENT: The result is '{response:?}'");
assert_eq!(response.unwrap(), vec![10, 7777, 8888, 40]);
// 读取无效地址
println!("CLIENT: Reading nonexistent holding register address... (should return IllegalDataAddress)");
let response = ctx.read_holding_registers(0x100, 1).await.unwrap();
println!("CLIENT: The result is '{response:?}'");
assert!(matches!(response, Err(Exception::IllegalDataAddress)));
println!("CLIENT: Done.")
},
tokio::time::sleep(Duration::from_secs(5))
};
}

Take a look at this similar error;

error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
1 | fn foo() {
  | -------- this function should return `Result` or `Option` to accept `?`
2 |     fn n() -> Result<(),()> { Ok(()) }
3 |     n()?;
  |        ^ cannot use the `?` operator in a function that returns `()`

It is hopefully more obvious what to do.

For you case read the join documentation to confirm it is what you want that deal with its return.

1 Like

Welcome to the forum!

Just a note: when you post in the future please format your code as described here so it is more readable.

2 Likes

Sorry, I'm not very familiar with using Markdown yet, I'll pay attention to it next time

I seem to understand something, thank you. I'll keep learning!