Hi, I'm trying to figure out a way around a problem without using clone() since it slows down the code.
let schnorr_apk_var = UInt8::<ConstraintF<C>>::new_witness_vec (
cs.clone(),
{
let apk = self.schnorr_apk.as_ref().unwrap_or(&default_pubkey);
let mut h_vec = vec![0u8; 32];
apk.serialize(&mut h_vec[..]).unwrap();
&h_vec.clone()
}
).unwrap();
If I return just &h_vec, it errors saying ``h_vecdoes not live long enough. borrowed value does not live long enough. main.rs(210, 13):h_vecdropped here while still borrowed main.rs(204, 21): bindingh_vec declared here main.rs(198, 31): borrow later used by call
Is there a way to resolve this without returning a clone?
Take the above code and put it before the call to new_witness_vec. Then you can pass &h_vec. h_vec itself must continue to exist (not go out of scope) during the call.
Or you can take the reference outside the block, so the place being referenced is a temporary belonging to the outer scope rather than a local variable of the block:
let schnorr_apk_var = UInt8::<ConstraintF<C>>::new_witness_vec (
cs.clone(),
&{
let apk = self.schnorr_apk.as_ref().unwrap_or(&default_pubkey);
let mut h_vec = vec![0u8; 32];
apk.serialize(&mut h_vec[..]).unwrap();
h_vec
},
).unwrap();
Randomly notices something unrelated to the question
let mut h_vec = vec![0u8; 32];
apk.serialize(&mut h_vec[..]).unwrap();
So you're passing in a &mut [u8], yeah? You probably don't need vec! here; just use an array.
let mut h_vec = [0u8; 32];
That might not work if new_witness_vec requires a &Vec<u8>. If it does, and you control that function too, change it to take a &[u8]. Requiring a &Vec<u8> gains you nothing,[1] is less general than &[u8], and adds indirection as well.
besides the ability to query a Vec capacity which you cannot change âŠī¸
I do want to add that in general, most clone()s are very cheap relative to the rest of the program logic.
See if you can avoid them easily, sure, but you shouldn't normally worry about contorting your code until you can actually measure the impact, like with any performance consideration.
Even if copying some T is very expensive, you can often just wrap it in an Rc/Arc and clone that instead.
let schnorr_apk_var = UInt8::<ConstraintF<C>>::new_witness_vec (
cs.clone(),
{
let apk = self.schnorr_apk.as_ref().unwrap_or(&default_pubkey);
let mut h_vec = vec![0u8; 32];
apk.serialize(&mut h_vec[..]).unwrap();
// Note the braces!
&{ h_vec }
}
).unwrap();
The reason that the simple &h_vec example doesn't work is that h_vec is defined within the scope, and must be dropped on scope exit, so you can't return a reference to it. But, the lifetime of the last expression in a block (which is returned) is actually extended beyond the block itself. You just need to make sure that nothing in that expression is scoped within the block.
This is why &h_vec_clone() works: you create a new h_vec.clone() value, and it will live as long as the block itself. Degenerately, this is also why &{ ... ; h_vec } works: it explicitly moves h_vec out of the scope, creating a new value. And the example above is just a simple, if obscure, way to force the value to move.
But of course you shouldn't actually bother with either of those in real code. Just extract the block to a sequence of statements before the function call like @jumpnbrownweasel, and use [u8; 32] instead of Vec<u8> as @quinedot suggested.