I've learned from book (and other resources), which suggested that it's better to split a program into a library and a binary which using this library.
So I have the following code:
- main.rs
let client = Client::new(address)?;
client.sync_forever()?
- lib.rs
struct Client {
..
}
impl Client {
pub fn new(..) {}
pub fn sync_forever() -> Result<()> {
// so much logic in the sync forever, let's says that there are 100 lines inside here.
// and many function call can return a result.
let file = open(file_name)?;
// ....
let conn = connect(address)?;
// ....
let file2 = open(file_name2)?;
// ...
// interactive with server..
Ok()
}
}
What I'm trying to to is delegate the main login to Client::sync_forever
, which means that Client::sync_forever
do so..so many things, includes:
- open the local cache file.
- make connection to server.
- interactive with server to sync data from server.
The problem is that when sync_forever
is very likely to return a Err
, which can because of server is down, or file doesn't exists, or something else.
But in the binary, it can just show me that the sync_forever
failed. And I don't know which line in the sync_forever
cause it returns a Err
, and it makes me extremely hard to debug for my code.
In other languages(like python), I have a backtrace, which helps me to identify which line cause the problem, but in here, if I'm using client.sync_forever().unwrap()
, the backtrace just stop on this statement, and I'm hardly to know what happened inside client.sync_forever()
I think I'm doing something wrong here, but I don't know how to make it right, would you please give me any advice about this kind of error handling?