Reputation: 2260
This question is in relation to the question asked here: How to declare a variable but not assign it?
My problem is slightly different. MRE:
let var: MyGenericType;
for value in vec_of_values_of_my_generic_type {
// one of the values is mathematically guaranteed to meet this condition because the vector is special
if <value meets a certain condition> {
var = value;
}
}
<use var>
Error:
error[E0381]: used binding `var` is possibly-uninitialized
--> example/src/lib.rs:127:23
|
120 | let var: MyGenericType;
| -- binding declared here but left uninitialized
...
123 | var = value;
| -- binding initialized here in some conditions
...
127 | foo(var);
| ^^ `var` used here but it is possibly-uninitialized
How do I fix this?
Upvotes: 1
Views: 82
Reputation: 18381
The answer to your literal question on how you can provide the compiler with a certain guarantee that it can't prove by itself - this is what unsafe {}
is for. It is literally telling the compiler "Here is some code that you don't have enough information about to tell whether it is safe or not. But I have this information and can assure you that it is indeed safe!". Here, you can use a special MaybeUninit
type wrapper to kind of emulate the behavior you are asking for:
use std::mem::MaybeUninit;
struct MyGenericType;
fn foo(v: MyGenericType) { unimplemented!() }
fn get_vec() -> Vec<MyGenericType> { unimplemented!() }
fn condition(v: &MyGenericType) -> bool { unimplemented!() }
fn main() {
let vec_of_values_of_my_generic_type = get_vec();
let mut var: MaybeUninit<MyGenericType> = MaybeUninit::uninit();
for value in vec_of_values_of_my_generic_type {
if condition(&value) {
var.write(value);
}
}
unsafe{ foo(var.assume_init()) };
}
Here, you are literally telling the compiler: "Assume that the variable is initialized". And since MaybeUninit::assume_init()
is an unsafe
function, you have no choice but wrap it in the unsafe {}
block to tell the compiler that you are providing the guarantees.
(You can do similar thing with the unsafe Option::unwrap_unchecked
, if you instead wrap the value into Option
).
Upvotes: 1
Reputation: 60497
If the structure of your code means the compiler can't be sure your value is initialized, use an Option
:
let mut var: Option<MyGenericType> = None;
for value in vec_of_values_of_my_generic_type {
if <value meets a certain condition> {
var = Some(value);
}
}
let var = var.expect("my generic type not set");
The expect()
pulls the value out of the Option
and panics with that message if it was never set.
Upvotes: 0
Reputation: 27552
Use the right tool for the job, here that would be Iterator::find
, instead of manually looping:
let var = vec_of_values_of_my_generic_type
.into_iter()
.find(|value| <value meets a certain condition>)
.unwrap();
Upvotes: 2