I'm having this error I can't seem to understand when dealing with match in a function, so currently I have of string tuples: let mut bitmap_point: Vec<(&str, &str)> = vec![]; and I want to use this in a function convert_to_binary, so I declared this:
fn convert_to_binary_string(tup: &(&str,&str) ) -> String{
let mut stringval: String =
match tup {
&(x,y) => from_str(x)
};
return stringval;
}
however upon calling the function with
let h = convert_to_binary_string( bitmap_point.get(0) );
I get the error :
>rustc main.rs
main.rs:12:3: 14:4 error: mismatched types: expected `collections::string::String` but found `core::option::Option<<generic #5>>` (expected struct collections::string::String but found enum core::option::Option)
main.rs:12 match tup {
main.rs:13 &(x,y) => from_str(x)
main.rs:14 };
main.rs:13:15: 13:23 error: cannot determine a type for this bounded type parame
ter: unconstrained type
main.rs:13 &(x,y) => from_str(x)
^~~~~~~~
could anyone explain what I'm going wrong?
You’re going about this the wrong way. If you merely want to convert a &str (a string slice) into a String (an owned strng), you should use the .to_string() method or String::from_str(str).
The FromStr trait is based around the Option type for conversions where not all inputs have a valid output—e.g. from_str::<int>("four") will return None because it can only cope with number literals. Where you’re turning something into a string, there are no failure cases, and from_str(str).unwrap() is a messy way of doing it.
Here is more idiomatic code to achieve your goal (using ref1()):
fn convert_to_binary_string(tup: &(&str, &str)) -> String {
tup.ref1().to_string()
}
This could easily be rewritten without ref1() using matching, as you have done, or a simple let binding:
fn convert_to_binary_string(tup: &(&str, &str)) -> String {
let &(x, _) = tup;
x.to_string()
}
But as a general rule, you should probably not be using tuples anyway—it’s normally a better idea to use a structure with meaningfully named fields, e.g.
struct Foo<'a> {
x: &'a str,
y: &'a str,
}
… then it would have been
fn convert_to_binary_string(foo: &Foo) -> String {
foo.x.to_string()
}
And at that stage you can probably drop the method altogether.
Ok so the answer just took a simple documentation search and I found the answer, my issue was that from_str(&str) return -> Option<T> where the value could either be Some or None. This was why I was receiving the Option error as shown above.
To fix this I checkout out rust's documentation and found a function unwrap() which could pull T out of the option variable. Everything works as expected and my final function is:
fn convert_to_binary_string(tup: &(&str,&str) ) -> String{
let mut stringval: String =
match tup {
&(x,y) => from_str(x).unwrap()
};
return stringval;
}
Related
I have a macro with a path parameter and now I want to call it through a method. However I have a hard time figuring out the parameter type of the of the method parameter that would be passed as a macro parameter.
Below is simple repro. This example use case doesn't make sense but it shows my problem clearly.
Following works:
fn main() {
let val = get_value!(true, DataValue::Int).unwrap();
println!("{}", val);
}
#[macro_export]
macro_rules! get_value {
( $rs: expr, $data_value_type: path ) => {{
let rand_val = return_data_value($rs);
if let $data_value_type(val) = rand_val {
Ok(val)
} else {
Err("This would not work")
}
}};
}
fn return_data_value(random_select: bool) -> DataValue {
if random_select {
DataValue::Int(1)
} else {
DataValue::Float(2.3)
}
}
enum DataValue {
Int(i32),
Float(f64),
String(String),
Bool(bool),
}
Now I want to create a function that calls the macro: (In the real world scenario this would be a much more complex one, but this shows the problem I have)
fn invoke_macro(random_select: bool, fun: <What type?>) -> i32 {
get_value!(random_select, fun).unwrap()
}
So here, what is the type of the parameter fun should be? Whatever I did so far gave me following error:
error: expected tuple struct or tuple variant, found local variable `fun`
label: not a tuple struct or tuple variant
Compiler tells me that the type of $data_value_type (macro parameter) for this particular invocation is fn(i32) -> DataValue {DataValue::Int} but I don't know how I can use that to figure out the parameter type.
You cannot. Not every macro can be made into a function, since macros can do syntax transformations and functions cannot.
DataValue::Int (for instance) is a function, like any tuple struct/enum variant, and that's why the compiler says this is its type. This function allows you to create the variant, like in (playground):
#[derive(Debug)]
struct S(i32);
let f: fn(i32) -> S = S;
let s = f(123);
dbg!(s);
But here, you don't use it as a function, but rather for pattern matching. This does not have a type and cannot be expressed.
I'm working thru some programming exercises on Exercism when I ran into this problem. It's not clear to me why the type of the closure set to for_each() even matters.Here's the entire Rust program:
use std::collections::HashSet;
// reformat(word) returns a tuple mapping its argument to (lowercase, sorted_lowercase)
fn reformat(word: &str) -> (String,String) {
let lower = word.to_lowercase();
let mut char_vec : Vec<char> = lower.chars().collect();
char_vec.sort_unstable();
let sorted : String = char_vec.iter().collect();
(lower,sorted)
}
// Items in 'possible_anagrams' will be added to the set if they contain all of the
// same characters as 'word' but arranged in a different order.
fn anagrams_for<'a>(word: &str, possible_anagrams: &'a [&str]) -> HashSet<&'a str> {
let mut set = HashSet::<&str>::new();
let w = reformat(word);
let is_anagram = |x:&str|->bool{let t=reformat(x);w.1==t.1&&w.0!=t.0};
possible_anagrams.iter().filter(|x|is_anagram(x)).for_each(|x| set.insert(x));
set
}
fn main() {
let a : [&str; 4] = ["FRBA", "Braf", "wut", "batt"];
println!("{:#?}", anagrams_for("Frab", &a));
}
I get an error message about the argument to the for_each() here:
|
18 | possible_anagrams.iter().filter(|x|is_anagram(x)).for_each(|x| set.insert(x));
| ^^^^^^^^^^^^^
expected `()`, found `bool`
The error message is not at all clear to me. I've tried various remedies but any change I make seems to make matters worse, i.e., more error messages.
I have a completely different manifestation of the anagrams_for() function that does work properly. So as far as the coding exercise goes, I have solved it via the following version of this function:
pub fn anagrams_for<'a>(word: &str, possible_anagrams: &'a[&str]) -> HashSet<&'a str> {
let mut set = HashSet::<&str>::new();
let w = reformat(word);
for x in possible_anagrams {
let test = reformat(x);
if w.1 == test.1 && w.0 != test.0 {
set.insert(x);
}
}
set
}
This one functions as I want. I've included it here as an example of what I want the so-far-not-working code to do.
HashSet::insert() returns bool (true if the value was already in the set).
Iterator::for_each() expects its closure to return the unit type (), or "nothing" (void in C).
Rust is expression-oriented: (almost) everything is an expression. Closures (and functions) returns the value of their last expression. That is, || expr is the same as || { return expr; }, and thus your closure returns the return value of insert() - a bool, while for_each() expects it to return ().
The fix is simple: you just need to discard insert()'s return value. It is done by making it into a statement, by appending a semicolon to it. This will also require you to use a block:
possible_anagrams.iter().filter(|x| is_anagram(x)).for_each(|x| { set.insert(x); });
I've started to learn Rust last week, by reading books and articles, and trying to convert some code from other languages at the same time.
I came across a situation which I'm trying to exemplify through the code below (which is a simplified version of what I was trying to convert from another language):
#[derive(Debug)]
struct InvalidStringSize;
impl std::fmt::Display for InvalidStringSize {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "string is too short")
}
}
impl std::error::Error for InvalidStringSize {}
pub fn extract_codes_as_ints(
message: String,
) -> Result<(i32, i32, i32), Box<dyn std::error::Error>> {
if message.len() < 20 {
return Err(Box::new(InvalidStringSize {}));
}
let code1: i32 = message[0..3].trim().parse()?;
let code2: i32 = message[9..14].trim().parse()?;
let code3: i32 = message[17..20].trim().parse()?;
Ok((code1, code2, code3))
}
So basically I want to extract 3 integers from specific positions of the given string (I could also try to check the other characters for some patterns, but I've left that part out).
I was wondering, is there a way to "catch" or verify all three results of the parse calls at the same time? I don't want to add a match block for each, I'd just like to check if anyone resulted in an error, and return another error in that case. Makes sense?
The only solution I could think of so far would be to create another function with all parses, and match its result. Is there any other way to do this?
Also, any feedback/suggestions on other parts of the code is very welcome, I'm struggling to find out the "right way" to do things in Rust.
The idiomatic way to accomplish this is to define your own error type and return it, with a From<T> implementation for each error type T that can occur in your function. The ? operator will do .into() conversions to match the error type your function is declared to return.
A boxed error is overkill here; just declare an enum listing all of the ways the function can fail. The variant for an integer parse error can even capture the caught error.
use std::fmt::{Display, Formatter, Error as FmtError};
use std::error::Error;
use std::num::ParseIntError;
#[derive(Debug, Clone)]
pub enum ExtractCodeError {
InvalidStringSize,
InvalidInteger(ParseIntError),
}
impl From<ParseIntError> for ExtractCodeError {
fn from(e: ParseIntError) -> Self {
Self::InvalidInteger(e)
}
}
impl Error for ExtractCodeError {}
impl Display for ExtractCodeError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::InvalidStringSize => write!(f, "string is too short"),
Self::InvalidInteger(e) => write!(f, "invalid integer: {}", e)
}
}
}
Now we just need to change your function's return type and have it return ExtractCodeError::InvalidStringSize when the length is too short. Nothing else needs to change as a ParseIntError is automatically converted into an ExtractCodeError:
pub fn extract_codes_as_ints(
message: String,
) -> Result<(i32, i32, i32), ExtractCodeError> {
if message.len() < 20 {
return Err(ExtractCodeError::InvalidStringSize);
}
let code1: i32 = message[0..3].trim().parse()?;
let code2: i32 = message[9..14].trim().parse()?;
let code3: i32 = message[17..20].trim().parse()?;
Ok((code1, code2, code3))
}
As an added bonus, callers of this function will be able to inspect errors more easily than with a boxed dyn Error.
In more complex cases, such as where you'd want to tweak the error slightly for each possible occurrence of a ParseIntError, you can use .map_err() on results to transform the error. For example:
something_that_can_fail.map_err(|e| SomeOtherError::Foo(e))?;
I'm reading the documentation for File:
//..
let mut file = File::create("foo.txt")?;
//..
What is the ? in this line? I do not recall seeing it in the Rust Book before.
As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
when writing the code you cannot accidentally forget to deal with the error,
when reading the code you can immediately see that there is a potential for error right here.
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ? does here is equivalent to the match statement above with an addition. In short:
It unpacks the Result if OK
It returns the error if not, calling From::from on the error value to potentially convert it to another type.
It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.
One example of the magic is that this also works for Option:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.
See also:
Is the question mark operator ? equivalent to the try! macro?
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
It is a postfix operator that unwraps Result<T, E> and Option<T> values.
If applied to Result<T, E>, it unwraps the result and gives you the inner value, propagating the error to the calling function.
let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
When applied to an Option<T>, it propagates None to the caller, leaving you the content of the Some branch to deal with.
let val = Some(42)?;
println!("{:?}", val); // 42
The ? operator can only be used in a function that returns Result or Option like so:
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number = "42".parse::<i32>()?;
println!("{:?}", number);
Ok(())
}
It is a convenience offered by Rust, that eliminates boilerplate code and makes function's implementation simpler.
It is used for propagating errors. Sometimes we write code that might fail but we do not want to catch and handle error immediately. Your code will not be readable if you have too much code to handle the error in every place. Instead, if an error occurs, we might want to let our caller deal with it. We want errors to propagate up the call stack.
// file type is Result if "?" is not used
// file:Result<File,Error>
let mut file = File::create("foo.txt");
// file type is File if "?" is used
// file:File
let mut file = File::create("foo.txt")?;
// if an error occurs, code after this line will not be executed
// function will return the error
The behavior of ? depends on whether this function returns a successful result or an error result:
If it is a success, it unwraps the Result to get the success value inside. Value is assigned to the variable file
If the result is an error, the error is NOT assigned to the variable file. Error is returned by the function to the caller
Using ? same as this code
let mut file = match File::create("foo.txt") {
Err(why) => panic!("couldn't create {}: {}", display, why),
Ok(file) => file,
};
? also works similarly with the Option type. In a function that returns Option, you
can use ? to unwrap a value and return early in the case of None :
The existing answers are all great! I would like to give a small code snippet to demo the use of From::from() behand this question mark:
fn _parse(str: &str) -> Result<i32, &str> {
if let Ok(num) = str.parse::<i32>() {
Ok(num)
} else {
Err(str)
}
}
fn parse(str: &str) -> Result<(), String> {
let num = _parse(str)?;
println!("{}", num);
Ok(())
}
The use of ? in function parse() can be manually rewritten as:
fn parse(str: &str) -> Result<(), String> {
match _parse(str) {
Ok(n) => {
println!("{}", n);
Ok(())
}
Err(str) => Err(<String as From<&str>>::from(str)),
}
}
I'm starting to get comfortable with Rust, but there are still some things that are really tripping me up with lifetimes. In this particular case, what I want to do is have an enum which may have different types wrapped as a generic parameter class to create strongly typed query parameters in a URL, though the specific use case is irrelevant, and return a conversion of that wrapped value into an &str. Here's an example of what I want to do:
enum Param<'a> {
MyBool(bool),
MyLong(i64),
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, &'a str) {
match self {
Param::MyBool(b) => ("my_bool", &b.to_string()), // clearly wrong
Param::MyLong(i) => ("my_long", &i.to_string()), // clearly wrong
Param::Value(s) => ("my_str", s),
}
}
}
What I ended up doing is this to deal with the obvious lifetime issue (and yes, it's obvious to me why the lifetime isn't long enough for the into() function):
enum Param<'a> {
MyBool(&'a str), // no more static typing :(
MyLong(&'a str), // no more static typing :(
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, &'a str) {
match self {
Param::MyBool(b) => ("my_bool", b),
Param::MyLong(i) => ("my_long", i),
Param::Value(s) => ("my_str", s),
}
}
}
This seems like an ugly workaround in a case where what I really want to do is guarantee the static typing of certain params, b/c now it's the constructor of the enum that's responsible for the proper type conversion. Curious if there is a way to do this... and yes, at some point I need &str as that is a parameter elsewhere, specifically:
let body = url::form_urlencoded::serialize(
vec![Param::MyBool(&true.to_string()).
into()].
into_iter());
I went through a whole bunch of things like trying to return String instead of &str from into(), but that only caused conversion issues down the line with a map() of String -> &str. Having the tuple correct from the start is the easiest thing, rather than fighting the compiler at every turn after that.
-- update--
Ok, so I went back to a (String,String) tuple in the into() function for the enum. It turns out that there is an "owned" version of the url::form_urlencoded::serialize() function which this is compatible with.
pub fn serialize_owned(pairs: &[(String, String)]) -> String
But, now I'm also trying to use the same pattern for the query string in the hyper::URL, specifically:
fn set_query_from_pairs<'a, I>(&mut self, pairs: I)
where I: Iterator<Item=(&'a str, &'a str)>
and then I try to use map() on the iterator that I have from the (String,String) tuple:
params: Iterator<Item=(String, String)>
url.set_query_from_pairs(params.map(|x: (String, String)| ->
(&str, &str) { let (ref k, ref v) = x; (k, v) } ));
But this gets error: x.0 does not live long enough. Ref seems correct in this case, right? If I don't use ref, then it's k/v that don't live long enough. Is there something 'simple' that I'm missing in this?
It is not really clear why you can't do this:
enum Param<'a> {
MyBool(bool),
MyLong(i64),
MyStr(&'a str),
}
impl<'a> Param<'a> {
fn into(self) -> (&'static str, String) {
match self {
Param::MyBool(b) => ("my_bool", b.to_string()),
Param::MyLong(i) => ("my_long", i.to_string()),
Param::MyStr(s) => ("my_str", s.into()),
}
}
}
(into() for &str -> String conversion is slightly more efficient than to_string())
You can always get a &str from String, e.g. with deref coercion or explicit slicing.