Hello world. I'm getting the error used binding is possibly-uninitialized
. Because the initialization of the variable is done inside condition blocks. But all the cases in which there is no initialization, are also cases where the program display an error message and exits, So there is nothing wrong. But how to tell the compiler that I'm in control and doesn't have to care ?
Demonstrate this with some minimal example code, otherwise it is difficult to give you advice.
You might be using a function to do the “display an error message and exit” action. If you do that, make sure to annotate such a function with a -> !
“this function never returns” return type.
// fails
fn display_error_and_exit() {
panic!("bye!");
}
fn demo(x: bool) {
let binding;
if x {
binding = 42;
} else {
display_error_and_exit();
}
let _useage = binding; // error[E0381]: used binding `binding` is possibly-uninitialized
}
// works
fn display_error_and_exit() -> ! {
panic!("bye!");
}
fn demo(x: bool) {
let binding;
if x {
binding = 42;
} else {
display_error_and_exit();
}
let _useage = binding;
}
If that’s not the problem here, then please give more information on what the code actually looks like
let slugified: String;
if args.contains("docname") {
if !args.get("docname").is_a_good_docname() {
eprint!("Bad Doc name");
std::process::exit(1);
}
slugified = slugify(args.get("docname"));
}
else {
let docname = ask_to_user("Choose a docname");
if !docname.is_a_good_docname() {
eprint!("Bad Doc name");
std::process::exit(1);
}
slugified = slugify(docname);
}
I don't use panic!
because according to what I read, it's for bug in my code, not for user errors. Is it right ?
The code you posed clearly initializes slugified
in both branches, so where is the error coming from? Could you run cargo check
and post the (relevant) full error message?
error[E0381]: used binding `dest_parent` is possibly-uninitialized
--> src/create.rs:220:28
|
66 | let dest_parent: PathBuf;
| ----------- binding declared here but left uninitialized
...
148 | dest_parent = temp_parent.canonicalize().unwrap();
| ----------- binding initialized here in some conditions
...
220 | println!("folder: {:#?}", dest_parent);
| ^^^^^^^^^^^ `dest_parent` used here but it is possibly-uninitialized
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0381`.
warning: `orixdb` (bin "orixdb") generated 8 warnings
error: could not compile `orixdb` due to previous error; 8 warnings emitted
I see… if it’s possible to just post the relevant code section between lines 66 and 220, I’ll gladly help spotting the reason why rustc doesn’t understand your logic, and suggest workarounds
I'm going to commit and push so that you will see the full code
As you can see, the code sample that I posted earlier was just a very very simplified version of the real code.
I see. The compiler cannot understand the connection between the bool dest_exists
and whether dest_parent
is initialized. There are two possible workaround.
First option: Combine dest_parent: bool
and dest_parent: String
into a single dest_parent_or_exists: Option<String>
, and use dest_parent_or_exists.is_none()
instead of dest_exists
. (Feel free to re-name it to something shorter if you like!)
I.e.
dest_exists = true;
becomes
dest_parent_or_exists = None;
and
dest_parent = …;
dest_exists = false;
becomes
dest_parent_or_exists = Some(…);
and
if !dest_exists { println!("folder: {:#?}", dest_parent) };
becomes
if let Some(parent) = &dest_parent_or_exists { println!("folder: {:#?}", parent) };
Second option, if you keep the logic as-is, you could still use an Option
for dest_parent
: either initialized with None
on declaration, and made mutable, or initialized with None
in every path; and then unwrap in the !dest_exist
path. I find the first approach to be preferrable though Less potential for panicking logic errors.
Thank you
I know this question is off-topic, but globally how is the code that I'm writing ? (I'm new to rust)
I don’t have time for much review right now. Regarding the exit
usage… in principle, it has the downside that destructors for local variables won’t be run anymore before exiting, on the other hand that might not be necessary. Nonetheless, you can alternatively change the signature of (both the real and all the sub-command) main
function to be (…) -> std::process::ExitCode
, and return ExitCode::FAILURE
or ExitCode::SUCCESS
as appropiate.
Typical alternative error handling approaches would/could include that the error printing, too, would be moved up to the top level; to make life easy, it can be useful to use a catch-all error type as offered by the crates anyhow
or eyre
(I haven’t used eyre
myself yet, but heard people say it creates nice looking error messages), then the return type of main
would be -> Result<(), anyhow::Error>
or -> Result<(), eyre::Report>
.
Glancing at the code a bit, one small thing I noticed:
if matches.contains_id("folder") {
let folder = matches.get_one::<String>("folder")
.unwrap()
;
…
} else {
…
}
which can probably be improved to
if let Some(folder) = matches.get_one::<String>("folder") {
…
} else {
…
}
Thanks for the review . I'll correct all that.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.