I have a rust program that has a function
‘is_input_sanitized’ that takes an input
String m, and checks if the input is free of special characters.The method is being used on a separate function in the following way.
let a = match is_input_sanitized(m) {
Ok(m) => m,
Err(_) => { return Err("error"); },
};
I am trying to convert this snippet into using ‘unwrap_or_else’ which will return an error when the input is not sanitized.I have read the documentation and have not been able to decipher a proper way to achieve this. Is this conversion possible?
unwrap_or_else is for extracting Result values. It sounds to me like you don't want to extract the result, so much as make a new one and propagate errors. You have two different things you want to do here. The first is that you want to change the error from whatever it started as (indicating by your _ in the pattern match) to something you control, and the second is that you want to return errors.
Replacing the error can be done with map_err, which takes a function (such as a closure) and applies that function to the error if the Result is an Err. If the result is Ok, then it returns the current Result unmodified.
The second problem, returning on Err, is exactly what the question mark operator was invented for.
Chaining results using match can get pretty untidy; luckily, the ? operator can be used to make things pretty again. ? is used at the end of an expression returning a Result, and is equivalent to a match expression, where the Err(err) branch expands to an early return Err(From::from(err)), and the Ok(ok) branch expands to an ok expression.
So what you're looking for is
let a = is_input_sanitized(m).map_err(|_| "error")?;
Related
I'm in progress of learning Rust and I'm trying to apply similar style I'm using with C++. With C++ I would be using RAII and exceptions and the closest I can get with Rust is RAII combined with early return with error Result. As such, when I write code such as
fn parse_meminfo() -> Result<Meminfo, io::Error> {
// ...
let file = File::open("/proc/meminfo")?;
for line in io::BufReader::new(file).lines() {
let line = line?;
// ...
Is it possible to somehow avoid the fragment let line = line?; of code? I already tried
for line in io::BufReader::new(file).lines()?
and
for line? in io::BufReader::new(file).lines()
and
for Ok(line) in io::BufReader::new(file).lines()
and
for line in io::BufReader::new(file).lines().expect("failed to read line")
but rustc wasn't happy with any of those. First and fourth have the test in logically wrong position because ? and expect() are testing the iterator instead of the item, if I've understood correctly. Second was syntax error, and the syntax Ok(line) is not happy to ignore the error because that doesn't mean early return. I would like to have early return with the error if the iterator in the loop gives an error and adding one extra line of code just for that seems silly and that test seems a bit detached from the actual loop. Can you suggest anything better? If the let line = line?; is indeed the idiomatic style, then I guess I would have to learn to love it.
Is it possible to somehow avoid the fragment let line = line?; of code?
Depending how you're using line, you could just tack on the ? over there. expr? simply desugars to1
match expr {
Ok(v) => v,
Err(e) => return e.into()
}
So you can see how the second attempt would not work (the left hand side of the for...in is an irrefutable pattern, not an expression).
The error handling here is largely orthogonal to the iteration, and iteration doesn't (at this juncture, though it seems unlikely that'll be added) have first-class support for error signaling, so you have an Iterator<Item=Result<...>> and you handle the Result however you wish.
If you don't care for the error reporting you could always .lines().map(|v| v.expect(...) and that'll immediately panic at the first error, but I don't know that that's what you're looking for.
1: that's not quite true anymore because of the `Try` trait, but close enough still
I want to check if the result from a request is having any issue. I categorize it into two: i) server error, ii) something else that is not a success. The third category is, result actually being a success. However, in the third category, I don't want to do anything.
So, my desirable code is:
if res.status().is_server_error() {
panic!("server error!");
} else if !(res.status.is_success()){
panic!("Something else happened. Status: {:?}", res.status());
} else{
pass;
}
I am aware of other ways to achieve this result: using match, ifs instead of if else if. But I wanted to learn what is the corresponding keyword of pass, like we have in Python. My aim is: if result is successful, just move along, if not, there are two ways to handle that panic.
Behold!
if predicate {
do_things();
} else {
// pass
}
Or even better
if predicate {
do_things();
} // pass
Or as I’ve recently taken to calling it the implicit + pass system
if predicate {
do_things();
}
In all seriousness there is no pass and no need for a pass in rust. As for why it exists in python, check out this answer
Python needs pass because it uses indentation-based blocks, so it requires some syntax to "do nothing". For example, this would be a syntax error in a Python program:
# syntax error - function definition cannot be empty
def ignore(_doc):
# do nothing
count = process_docs(docs, ignore) # just count the docs
The ignore function has to contain a block, which in turn must contain at least one statement. We could insert a dummy statement like None, but Python provides pass which compiles to nothing and signals the intention (to do nothing) to the human reader.
This is not needed in Rust because Rust uses braces for blocks, so one can always create an empty block simply using {}:
// no error - empty blocks are fine
fn ignore(_doc: &Document) {
// do nothing
}
let count = process_docs(docs, ignore); // just count the docs
Of course, in both idiomatic Python and Rust, one would use a closure for something as simple as the above ignore function, but there are still situations where pass and empty blocks are genuinely useful.
I'm trying to make an if statement comparing a String variable and a String to match exact values (without using match). Here is my code:
if &guess.trim().parse() == String::from("quit") { // TODO: Fix this
println!("Goodbye! The secret number was: {} and you attempted to guess it {} times!", secret_number, tries);
break;
}
guess is a String::new() which has been assigned a value through user input (io::stdin().read_line(&mut guess).expect("Unable to read line");)
When I run the code, I get an error from the above code snippet:
Does anyone know why I'm getting this error and how to fix it?
I have tried converting "quit" to String::from("quit") but it seems that the error is to do with the == and I'm not sure what &Result<_, _> is. Thanks!
In this situation parse() was superfluous, but in most other situations you resolve the error "something not implemented for Result" by extracting the actual value from the Result and using that rather than the Result itself. Your options for that are:
the ? operator to extract the value and propagate the error (if one occurred) to the caller,
the unwrap() or expect() methods to panic in case of error, and
pattern matching with match or if let, to handle the error case locally.
See the book chapter on Result for details.
Using if guess.trim() == "quit" fixed my problem. Thank you #eggyal!
I'm starting right now with coding on JS. There are a few things that I don't understand pretty well, and I'm a little bit confused because I have tried almost all, and I don't get to solve the error. Would someone provide me some help or guidance with this.
my code
function ImparPar(NumIp) {
if(NumIp % 2 === 0) {
return 'Par';
} else {
return 'Impar';
}
}
Your function definition (on Line 1) has the following:
The function keyword
A function name (ImparPar)
A formal parameter (NumIP)
All these make this a function definition.
When you are calling the function later on in the code (line 13) you just need to call it by name. e.g.:
ImparPar(2);
When you are calling a function, you pass it - what is called - an actual parameter (in your case 2).
When you prefix it with the function keyword, it is interpreted as a function definition and therefore does not expect an actual parameter, and instead expects a formal parameter.
If you remove the function keyword from line 13 it should work as expected for you, and just execute the function.
How can I know if I actually need to return an l-value when using FALLBACK?
I'm using return-rw but I'd like to only use return where possible. I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
Or (alternate plan B) can I attach a callback or something similar to my %!attrs to monitor for changes?
class Foo {
has %.attrs;
submethod BUILD { %!attrs{'bar'} = 'bar' }
# multi method FALLBACK(Str:D $name, *#rest) {
# say 'read-only';
# return %!attrs{$name} if %!attrs«$name»:exists;
# }
multi method FALLBACK(Str:D $name, *#rest) {
say 'read-write';
return-rw %!attrs{$name} if %!attrs«$name»:exists;
}
}
my $foo = Foo.new;
say $foo.bar;
$foo.bar = 'baz';
say $foo.bar;
This feels a bit like a X-Y question, so let's simplify the example, and see if that answers helps in your decisions.
First of all: if you return the "value" of a non-existing key in a hash, you are in fact returning a container that will auto-vivify the key in the hash when assigned to:
my %hash;
sub get($key) { return-rw %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
Please note that you need to use return-rw here to ensure the actual container is returned, rather than just the value in the container. Alternately, you can use the is raw trait, which allows you to just set the last value:
my %hash;
sub get($key) is raw { %hash{$key} }
get("foo") = 42;
dd %hash; # Hash %hash = {:foo(42)}
Note that you should not use return in that case, as that will still de-containerize again.
To get back to your question:
I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
class Foo {
has %!attrs;
has %!unexpected;
method TWEAK() { %!attrs<bar> = 'bar' }
method FALLBACK(Str:D $name, *#rest) is raw {
if %!attrs{$name}:exists {
%!attrs{$name}
}
else {
%!unexpected{$name}++;
Any
}
}
}
This would either return the container found in the hash, or record the access to the unknown key and return an immutable Any.
Regarding plan B, recording changes: for that you could use a Proxy object for that.
Hope this helps in your quest.
Liz's answer is full of useful info and you've accepted it but I thought the following might still be of interest.
How to know if returning an l-value ... ?
Let's start by ignoring the FALLBACK clause.
You would have to test the value. To deal with Scalars, you must test the .VAR of the value. (For non-Scalar values the .VAR acts like a "no op".) I think (but don't quote me) that Scalar|Array|Hash covers all the l-value super-types:
my \value = 42; # Int is an l-value is False
my \l-value-one = $; # Scalar is an l-value is True
my \l-value-too = #; # Array is an l-value is True
say "{.VAR.^name} is an l-value is {.VAR ~~ Scalar|Array|Hash}"
for value, l-value-one, l-value-too
How to know if returning an l-value when using FALLBACK?
Adding "when using FALLBACK" makes no difference to the answer.
How can I know if I actually need to return an l-value ... ?
Again, let's start by ignoring the FALLBACK clause.
This is a completely different question than "How to know if returning an l-value ... ?". I think it's the core of your question.
Afaik, the answer is, you need to anticipate how the returned value will be used. If there's any chance it'll be used as an l-value, and you want that usage to work, then you need to return an l-value. The language/compiler can't (or at least doesn't) help you make that decision.
Consider some related scenarios:
my $baz := foo.bar;
... (100s of lines of code) ...
$baz = 42;
Unless the first line returns an l-value, the second line will fail.
But the situation is actually much more immediate than that:
routine-foo = 42;
routine-foo is evaluated first, in its entirety, before the lhs = rhs expression is evaluated.
Unless the compiler's resolution of the routine-foo call somehow incorporated the fact that the very next thing to happen would be that the lhs will be assigned to, then there would be no way for a singly or multiply dispatched routine-foo to know whether it can safely return an r-value or must return an l-value.
And the compiler's resolution does not incorporate that. Thus, for example:
multi term:<bar> is rw { ... }
multi term:<bar> { ... }
bar = 99; # Ambiguous call to 'term:<bar>(...)'
I can imagine this one day (N years from now) being solved by a combination of allowing = to be an overloadable operator, robust macros that allow overloading of = being available, and routine resolution being modified so the above ambiguous call could do something equivalent to resolving to the is rw multi. But I doubt it will actually come to pass even with N=10. Perhaps there is another way but I can't think of one at the moment.
How can I know if I actually need to return an l-value when using FALLBACK?
Again, adding "when using FALLBACK" makes no difference to the answer.
I want to track if I've actually modified %!attrs or have only just read the value when FALLBACK was called.
When FALLBACK is called it doesn't know what context it's being called in -- r-value or l-value. Any modification comes after it has already returned.
In other words, whatever solution you come up with will being nothing to do per se with FALLBACK (even if you have to use it to implement some other aspect of whatever it is you're trying to do).
(Even if it were, I suspect trying to solve it via FALLBACK itself would just make matters worse. One can imagine writing two FALLBACK multis, one with an is rw trait, but, as explained above, my imagination doesn't stretch to that making any difference any time soon, if ever, and could only happen if the above imaginary things happened (the macros etc.) and the compiler was also modified to pay attention to the two FALLBACK multi variants, and I'm not at all meaning to suggest that that even makes sense.)
Plan B
Or (alternate plan B) can I attach a callback or something similar to my %!attrs to monitor for changes?
As Lizmat notes, that's the realm of Proxys. And thus your next SO question... :)