Closed greenpdx closed 7 years ago
Hi! I would guess that the reason for your ownership problems is that cmd
borrows from todo
(as_str
returns &str
), so you can't move todo
into cmd_hello
until cmd
is out of scope. A simple solution would be to convert the command to a String
by doing something like this:
let cmd = todo.get("cmd").unwrap().as_str().unwrap().to_owned();
// or
let cmd: String = todo.get("cmd").unwrap().as_str().unwrap().into();
// or
let cmd = String::from(todo.get("cmd").unwrap().as_str().unwrap());
// or
let cmd = todo.get("cmd").unwrap().as_str().unwrap().to_string();
Which one you pick is a matter of taste. :smile: I hope that helps!
Please let me confirm what you said. .to_owned() makes cmd the owner cmd: String = ....into() move it into cmd String::from() pulls ownership from todo .to_string() does it just convert or does it take ownership?
Next, if "cmd" is not found in todo.get(), None is returned, will it get a crash if None is returned?
They will all have the exact same result, just through slightly different paths.
to_owned()
uses the ToOwned
trait to turn a value into its owned counterpart. String
is the owned counterpart to &str
.into()
will use the Into
trait to make a conversion. The let cmd: String
part gives the compiler enough hints to know that it should be converted into a String
.String::from(...)
is exactly the same as the above variant, but "from the other end" using the From
trait. It's basically "make a String
from this".to_string()
converts anything that can be printed (like in println!("{}", x)
) to a String
. Since &str
can be printed, it can be converted to a String
.Next, if "cmd" is not found in todo.get(), None is returned, will it get a crash if None is returned?
Yes, and that's not particularly desirable in a web server. What you can do, since both of the unwrap
cases are for Option
, is sending a response to the user when something is not right:
let cmd = if let Some(cmd) = todo.get("cmd")and_then(|v| v.as_str()).and_then(String::from) {
cmd // just returns it to the variable
} else {
return Err(...); // something about "cmd" being a mandatory string
};
The .and_then(String::from)
is just the same thing as doing String::from(...)
on the content of the Option
, but without an extra closure/lambda. We are just passing the function in there instead.
(Updated with some links)
Thank you for helping. I have programmed in many languages and like the concepts of rust but getting my head around the syntax of rust is "interesting"
let cmd = if let Some(cmd) = todo.get("cmd")and_then(|v| v.as_str()).and_then(String::from) { cmd // just returns it to the variable
the if let Some(cmd) does the same thing as unwrap() ? it is needed because an Option is passed back.
todo.get("cmd") finds the object in todo.
and_then() returns None is "cmd" is not found or calls the |v| v.as_str() converting it &str that returns a Option.
the next andthen converts Option<&str> to Option
Sorry, .and_then(String::from)
should be .map(String::from)
. I suggest that you read about the methods of Option
in the documentation, where both of these are explained.
if let <pattern> = <expression> {
is like match
, but for only one case, so if let Some(x) = ... { x } else { 0 }
will result in x
if it gets Some
or 0
if it gets None
. You could say that it's like unwrap, but you can choose what to do in each case.
So the difference between map and and_then is map() just executes the function and and_then checks for None then executes the function.
I have copied the code in question here. I am still getting and error on passing context to cmd_hello(tnvdata, context, todo). the from_reader(context.body) takes some ownership. I understand that when I read the context.body I take ownership of part of context. I was thinking I could copy "todo" to something else but then how do I release the ownership of that todo taken from context.
so I would take copy release that is what I wanted to do in rdBody()
fn cmd_hello(tnvdata: &Database, context: Context, cmd: Value) -> Result<Option
fn rdBody(context: Context) -> Result<Option
fn tnv_post(tnvdata: &Database, context: Context) -> Result<Option
// let mut rslt = json!({"salt": "1023456", "nonce":"12345"}); // Ok(Some(serde_json::to_string(&rslt).unwrap())) }
So the difference between map and and_then is map() just executes the function and and_then checks for None then executes the function.
Nah, and_then
is like map
, but expects another Option
to be returned instead of just the value. That's why it's good for chaining operations that return Option
.
the from_reader(context.body) takes some ownership.
I didn't notice that. You don't have to move body out of context, you can use a reference: from_reader(&mut context.body)
I tried &context.body and it failed but &mut context.body works, why?
Because reading is an operation that changes the body. It consumes its content, so it has to be mutable.
That is because context.body is a reader stream. Ah!
I have only been programming rust for about a week. Talk about jumping into the deep end.
My final goal is to have a mongodb backed jsonrpc like server. Right now I am working on the login and session part. I am using tweetnacl as the javascript library. What is the best crypto library for rust that supports ed25519?
Thanks for all the help.
No problem! Feel free to ask again if you have any questions about Rustful.
Deep end or not, a clear goal and some determination will you far. It's at least a learning experience!
Unfortunately I don't really know much about the crypto ecosystem. Your best bet is to search crates.io and ask in the user forum or on Reddit.
Good luck!
I am new at rust and I am having ownership problems.
My json rps functions look this this,
I copied the the code from the todo.rs to parse the context.body let todo: Value = try!(serde_json::from_reader(context.body).maperr(|| Error::ParseError));
then I get the command let cmd = todo.get("cmd").unwrap().as_str().unwrap()
then send it to the correct handler match cmd { "hello" => cmdhello(data, context, todo), .... => Err(Error::CmdNotFound) }
I am getting ownership errors on both context and todo. I understand context.body is where I borrow context and todo.get() is where I borrow todo. BUt knowing where the problem is does not help.
Could some one please post a small snippet of code that I could use solve this problem.
I plan to use a HashMap later but for now just getting it working is more important.