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) {
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.")

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.


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!