Reverse a string in 0.10 - rust

I'm having trouble reversing a string in the newest version of rust, I saw this post but I'm still getting some errors. I'm trying to reverse a string and compare the two without any luck:
fn is_palindromic(num: int) -> bool {
let num_str = num.to_str();
let rev_num_str = num_str.chars_rev().collect();
if rev_num_str == num_str {
return true;
}else{
return false;
}
}
then I receive the error:
main.rs:8:28: 8:39 error: type `collections::string::String` does not implement
any method in scope named `chars_rev`
main.rs:8 let rev_num_str = num_str.chars_rev();

Many of the traditionally useful string methods are defined in the std::str::StrSlice trait. To get a slice from a String value, you can call the as_slice method. It looks like chars_rev is no longer defined in the StrSlice trait, but there is a chars method which returns an iterator Chars.
This particular iterator implements the DoubleEndedIterator trait, which means it can be reversed by calling rev. That should be all you need:
fn is_palindromic(num: int) -> bool {
let num_str = num.to_str();
let rev_num_str: String = num_str.as_slice().chars().rev().collect();
return rev_num_str == num_str;
}
fn main() {
println!("{}", is_palindromic(12321));
}
Note that I also added a type annotation to rev_num_str since the compiler can't infer its concrete type (collect is polymorphic and can build many different kinds of "container" values). You could alternatively instantiate collect specifically:
let rev_num_str = num_str.as_slice().chars().rev().collect::<String>();

Related

Generics<T> that accept String, &str and primitive value

I apologize in advance as this may somewhat dumb question.
I was trying to create the function that simply return the bool result of
whether the given value is prime number or not.
I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
pub fn prime<T>(val: T) -> bool
where T: ToPrimitive {
let val = val.to_i64().unwrap();
for i in 2..=val {
if val % i == 0 {
return false;
}
if i*i >= val {
break;
}
}
true
}
If you are concerned with performance, leave it as is. You are already accepting all integer types. Conversion from strings should happen elsewhere. (as already mentioned by the other answers)
That said, to actually fulfill your request, here is a horribly inefficient but simple solution to your problem :)
pub fn prime<T>(val: T) -> bool
where
T: ToString,
{
let val: u64 = val.to_string().parse().unwrap();
for i in 2..val {
if val % i == 0 {
return false;
}
if i * i >= val {
break;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
println!("{:?}", prime("17"));
println!("{:?}", prime(String::from("17")));
}
true
true
true
On a more serious note ... your own solution and all of the answers convert the input into another type.
If you skip that and instead use the given type directly, you could potentially get a speed boost.
For that to work, though, I had to switch from i * i >= val to ..=val.sqrt().
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
for i in num::range_inclusive(two, val.sqrt()) {
if val % i == T::zero() {
return false;
}
}
true
}
fn main() {
println!("{:?}", prime(17));
}
true
As a further note, you could rewrite the entire for loop with the all iterator method:
pub fn prime<T>(val: T) -> bool
where
T: num::PrimInt + num::integer::Roots,
{
let two = T::one() + T::one();
num::range_inclusive(two, val.sqrt()).all(|i| val % i != T::zero())
}
fn main() {
println!("{:?}", prime(17));
}
true
I wanted the function to both accept the String, &str and primitive value.
Is there anyway that I can make this possible.
You'd have to create your own trait to unify the feature: while Rust has grown the TryFrom trait, in the stdlib currently it's only used for faillible integer -> integer conversions (e.g. i64 to u8). String -> integer conversions remain on the older FromStr trait, and it's unclear that there's any plan to migrate.
I would agree with #cameron1024 though, doing this conversion in the callee increases the complexity without making much sense, if the callee takes a string I would expect it to handle and report validation / conversion errors to the source of the values. The prime of a string doesn't really make sense.
Firstly, do you really want to be able to check if strings are prime? You probably don't want someone to be able to write prime("hello").
Assuming you're fine with numbers, I'd just use Into<u128> as the trait bound:
fn prime<T: Into<u128>>(t: T) -> bool {
let val = t.into();
// rest of the logic
}
So what about strings and signed integers?
IMO, you should convert these at the call-site, which allows for better error handling, rather than just unwrap():
/// strings
prime("123".parse()?);
prime(String::from("123").parse()?);
/// signed ints
prime(u128::try_from(123i8)?);
This way, you can use ? to correctly handle errors, and make prime panic-free.
If you really want to not have to convert at the callsite, you could use a custom trait:
trait TryIntoU128 {
type Error;
fn try_into_u128(self) -> Result<u128, Self::Error>;
}
Then you could implement this on various types:
impl TryIntoU128 for String {
type Error = ParseIntError;
fn try_into_u128(self) -> Result<u128, Self::Error> {
self.parse()
}
}
// etc
Then you can use this trait bound for your prime function instead

Argument to for_each() function appears to be the wrong type

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); });

Finding string slices in an array of string slices

I have a large array of statically allocated string slices, defined like so:
const ARR: [&'static str; 50] = [...];
I'm then iterating through the array in what I assume is a normal manner (I'm new to Rust):
for el in ARR.iter() {
if el == target {
return true;
}
}
Unfortunately, I'm getting an error when I try to use eq():
error: the trait `core::cmp::PartialEq<str>` is not implemented for the type `&str`
Is there something in the standard library to compare string slices, or do I have to just iterate through and compare characters myself? And, for that matter, is there a better way to search for an element in an array than what I'm doing?
Thanks!
Here's how you could write your example:
const FRUITS: [&'static str; 3] = ["apple", "banana", "coconut"];
fn is_available(desired: &str) -> bool {
for &el in FRUITS.iter() {
// let () = el; // PROTIP
if el == desired {
return true;
}
}
false
}
See where I assigned el to ()? That's a little trick to see what the type of a variable is at some point. If you uncomment that, you'll get an error like:
error: mismatched types:
expected `&&str`,
found `()`
This lets you know what the types are. The second part is to look at the implementations of PartialEq for str, the important one being:
impl PartialEq<str> for str
So we bind el with a pattern that will automatically dereference it once for us. Then the comparison can take place, as we have a balanced amount of dereferencing to do:
for &el in FRUITS.iter() {
// ^~~ Here
But really, I'd write it like this:
static FRUITS: [&'static str; 3] = ["apple", "banana", "coconut"];
fn main() {
let desired = "apple";
let to_eat = FRUITS.iter().find(|&&f| f == desired);
println!("{:?}", to_eat);
let desired = "durian";
let to_eat = FRUITS.iter().find(|&&f| f == desired);
println!("{:?}", to_eat);
}
static creates an actual shared place in memory for the variable. const acts more like a C #define - the value is inserted everywhere it is used. Since find returns the item, we need it to have some storage that lasts for longer than the one expression.
IteratorExt::find also abstracts the work of finding a matching value (for some condition), and returns an Option denoting success / failure.

A built-in Object in Rust

Rust doesn't have built-in Object type I take it? If so, how do I, say, create a HashMap of "something" that in Java would be Object:
fn method1(my_hash_map: HashMap<&str, ???>) { ... } // Rust
void method1(Map<String, Object> myMap) { ... } // Java
If you want a HashMap that can mix values of many different types, you'll have to use Any. The most direct equivalent to Map<String, Object> would be HashMap<String, Box<Any>>. I switched &str to String because &str without a lifetime is probably not what you want and in any case even further removed from Java String than Rust's String already is.
However, if you simply don't care about the type of the values, it's simpler and more efficient to make method1 generic:
fn method1<T>(my_hash_map: HashMap<String, T>) { ... }
Of course, you can also add constraints T:Trait to do more interesting things with the values (cf. Object allows equality comparisons and hashing).
To expand on rightføld's comment, Any is the closest you can really get in Rust, though it does come with a major restriction: it is only implemented by types which satisfy the 'static lifetime; that is, you can't treat any type which contains non-static references as an Any.
A second complication is that Object in Java has reference semantics and gives you shared ownership. As such, you'd need something like Rc<RefCell<Any>> to get something roughly comparable. Note, however, that this is heavily discouraged since it basically moves a lot of checks to runtime. Something like this should be a fallback of last resort.
Finally, note that, insofar as I'm aware, there's no way to do a dynamic upcast on an Any to anything other than the erased type; so you can't take a reference to a value that, say, implements Show, turn it into an &Any, and then upcast to a &Show.
Better alternatives, if applicable, include generalising the value type (so use generic functions and structs), using an enum if there is a fixed, finite list of types you want to support, or write and implement a custom trait, in that order.
To give you an example of working with Any, however, I threw the following together. Note that we have to try explicitly upcasting to every supported type.
#![feature(if_let)]
use std::any::{Any, AnyRefExt};
use std::collections::HashMap;
fn main() {
let val_a = box "blah";
let val_b = box 42u;
let val_c = box 3.14159f64;
let mut map = HashMap::new();
map.insert("a".into_string(), val_a as Box<Any>);
map.insert("b".into_string(), val_b as Box<Any>);
map.insert("c".into_string(), val_c as Box<Any>);
println!("{}", map);
splang(&map);
}
fn splang(map: &HashMap<String, Box<Any>>) {
for (k, v) in map.iter() {
if let Some(v) = v.downcast_ref::<&str>() {
println!("[\"{}\"]: &str = \"{}\"", k, *v);
} else if let Some(v) = v.downcast_ref::<uint>() {
println!("[\"{}\"]: uint = {}", k, *v);
} else {
println!("[\"{}\"]: ? = {}", k, v);
}
}
}
When run, it outputs:
{c: Box<Any>, a: Box<Any>, b: Box<Any>}
["c"]: ? = Box<Any>
["a"]: &str = "blah"
["b"]: uint = 42

Match tuple error expected String but found Option<<generic #5>>

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;
}

Resources