I'm facing a problem where I have a structure (called HomotopyOptimizer
) which has a number of fields (some are borrowed). In HomotopyOptimizer
there is a method with argument &self mut
.
What I do is that I take some of the fields of my structure and either borrow them to other functions or move their ownership because I will not be needing them further.
Let me describe the situation with a graphic (I'll provide the code at the end):
My HomotopyOptimizer
has two fields: (i) one of type HomotopyProblem
and (ii) one of type &Cache
.
These, in turn are structures with certain fields. In particular, the HomotopyProblem
field has three fields.
I need to construct a structure of type Problem
using the fields of HomotopyProblem
and by borrowing the field of type Cache
from self
, however, Rust complains that I cannot borrow it because self itself has been borrowed previously (or at least it seems so).
My main question is whether I can move the ownership of fields of a structure without moving or lending the structure itself.
Let me present my code in reverse order. First the function in which I get the compilation error:
impl<'cache_lifetime,
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType, ParametricCostType>
HomotopyOptimizer<...same_as_above...>
where
ParametricPenaltyFunctionType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricGradientType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricCostType: Fn(&[f64], &[f64], &mut f64) -> Result<(), Error>,
ConstraintType: constraints::Constraint,
{
pub fn solve(&'cache_lifetime mut self, u: &mut [f64]) {
let p_ = [1., 2., 3.];
let f_ = |u: &[f64], cost: &mut f64| -> Result<(), Error> {
(self.homotopy_problem.parametric_cost)(u, &p_, cost)
};
let df_ = |u: &[f64], grad: &mut [f64]| -> Result<(), Error> {
(self.homotopy_problem.parametric_gradient)(u, &p_, grad)
};
let problem_ = Problem::new(&self.homotopy_problem.constraints, df_, f_);
let mut panoc_ = panoc::Optimizer::new(problem_, &mut self.panoc_cache);
panoc_.solve(u);
println!("u = {:#?}", u);
}
}
I get the following error:
Compiling optimization_engine v0.3.1 (/home/chung/NetBeansProjects/RUST/optimization-engine)
error[E0502]: cannot borrow `self.panoc_cache` as mutable because it is also borrowed as immutable
--> src/continuation/homotopy_optimizer.rs:83:63
|
75 | let f_ = |u: &[f64], cost: &mut f64| -> Result<(), Error> {
| ------------------------------------------------ immutable borrow occurs here
76 | (self.homotopy_problem.parametric_cost)(u, &p_, cost)
| ---- first borrow occurs due to use of `self` in closure
...
83 | let mut panoc_ = panoc::Optimizer::new(problem_, &mut self.panoc_cache);
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow later used by call
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
error: Could not compile `optimization_engine`.
warning: build failed, waiting for other jobs to finish...
error[E0502]: cannot borrow `self.panoc_cache` as mutable because it is also borrowed as immutable
--> src/continuation/homotopy_optimizer.rs:83:63
|
75 | let f_ = |u: &[f64], cost: &mut f64| -> Result<(), Error> {
| ------------------------------------------------ immutable borrow occurs here
76 | (self.homotopy_problem.parametric_cost)(u, &p_, cost)
| ---- first borrow occurs due to use of `self` in closure
...
83 | let mut panoc_ = panoc::Optimizer::new(problem_, &mut self.panoc_cache);
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
| |
| immutable borrow later used by call
error: aborting due to previous error
For more information about this error, try `rustc --explain E0502`.
error: Could not compile `optimization_engine`.
For completeness: The definition of HomotopyOptimizer is
pub struct HomotopyOptimizer<
'cache_lifetime,
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
> where
ParametricPenaltyFunctionType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricGradientType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricCostType: Fn(&[f64], &[f64], &mut f64) -> Result<(), Error>,
ConstraintType: constraints::Constraint,
{
homotopy_problem: HomotopyProblem<
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
>,
panoc_cache: &'cache_lifetime mut panoc::Cache,
}
and its constructor is
pub fn new(
homotopy_problem: HomotopyProblem<
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
>,
panoc_cache: &'cache_lifetime mut panoc::PANOCCache,
) -> HomotopyOptimizer<
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
> {
HomotopyOptimizer {
homotopy_problem: homotopy_problem,
panoc_cache: panoc_cache,
}
}
The definition of HomotopyProblem is
pub struct HomotopyProblem<
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
> where
ParametricPenaltyFunctionType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricGradientType: Fn(&[f64], &[f64], &mut [f64]) -> Result<(), Error>,
ParametricCostType: Fn(&[f64], &[f64], &mut f64) -> Result<(), Error>,
ConstraintType: constraints::Constraint,
{
pub(crate) constraints: ConstraintType,
pub(crate) parametric_gradient: ParametricGradientType,
pub(crate) parametric_cost: ParametricCostType,
pub(crate) penalty_function: ParametricPenaltyFunctionType,
idx: Vec<usize>,
from: Vec<f64>,
to: Vec<f64>,
transition_mode: Vec<i32>,
num_parameters: usize,
}
and its constructor is
pub fn new(
constraints: ConstraintType,
parametric_gradient: ParametricGradientType,
parametric_cost: ParametricCostType,
penalty_function: ParametricPenaltyFunctionType,
num_parameters: usize,
) -> HomotopyProblem<
ParametricPenaltyFunctionType,
ParametricGradientType,
ConstraintType,
ParametricCostType,
> {
HomotopyProblem {
constraints: constraints,
parametric_gradient: parametric_gradient,
parametric_cost: parametric_cost,
penalty_function: penalty_function,
idx: Vec::new(),
from: Vec::new(),
to: Vec::new(),
transition_mode: Vec::new(),
num_parameters: num_parameters,
}
}