Passing a variable to a function (which alters said variable) repeatedly

倖福魔咒の 提交于 2019-12-11 00:16:20

问题


I'm having a play with Rust and, probably biting off far more than I can chew, am trying to write a module that will encapsulate my database traffic for the rest of the application. The code I'm struggling with is the following:

pub fn create_statement(cypher: &str, params: &HashMap<&str, &str>) -> rusted_cypher::Statement {
    let mut statement = rusted_cypher::Statement::new(cypher);
    for (field, value) in params.iter() {
        statement.with_param(field.to_owned(), value.to_owned());
    }
    return statement;
}

This gives the following error: error[E0382]: use of moved value: statement. My searching has, I think, lead me to what this means (the Statement struct is not copyable, thus gets moved and is then ... effectively no longer accessible, I guess?), but I'm not sure how to get around it. Can anyone point me in the direction of a solution?


回答1:


I haven't used this API before but, according to its documentation:

This method consumes self and returns it with the parameter added, so the binding does not need to be mutable.

It isn't, as you say, that the struct is "not copyable", it's that the with_param method is intentionally written in such a way that it moves the value and takes ownership - we can also say that it consumes it. Consuming the value is a common thing to do in a builder-style API because it prevents you from having accidental half-built objects lying around. Each builder method will consume the object, during which time nothing else can access it, and then return it when it's finished so you can continue using it. From the documentation:

let statement = Statement::new("MATCH n RETURN n")
    .with_param("param1", "value1")?
    .with_param("param2", 2)?
    .with_param("param3", 3.0)?;

Each call to with_param consumes statement and then returns it so you can call with_param again.

Where this gets a bit tricky is that the result of the with_param is not a Statement, but a Result<Statement, JsonError>. Apparently adding a parameter could cause an error so the result is wrapped up to accommodate that possibility. That's what the ?s are for - they unwrap that result into the underlying value, or else propagate the error if that can't be done.

As one of the other answers already suggested, a better fix is to just use the set_parameters method, which will set them all in one go.

Another way to do it would be to use the return value of each call to with_param:

pub fn create_statement(cypher: &str, params: &HashMap<&str, &str>) -> rusted_cypher::Statement {
  let mut statement = rusted_cypher::Statement::new(cypher);
  for (field, value) in params.iter() {
      statement = statement.with_param(field.to_owned(), value.to_owned()).unwrap();
  }
  statement
}

When you use the return value, you have access to the value again, so you can keep on using it.

Notice that I used unwrap() to get the value from the Result. This is not good practice because it will cause a panic if the result is an error. I have done this here to focus on explaining move semantics without a digression into error handling, which is a topic by itself.




回答2:


While this doesn't answer your underlying question about passing a mutable value in the same way as your current code.

rusted-cypher::Statement has a set_parameters method which takes a &BTreeMap<String, T> as its only argument.

You can see this function in the rusted-cypher's source code.

A conceivable implementation:

pub fn create_statement(cypher: &str, params: &BTreeMap<&str, &str>) -> rusted_cypher::Statement {
   let mut statement = rusted_cypher::Statement::new(cypher);
   statement.set_parameters(params);
   statement
}


来源:https://stackoverflow.com/questions/44904677/passing-a-variable-to-a-function-which-alters-said-variable-repeatedly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!