Number -> string back to string.reverse -> number

I'm converting some Ruby/Crystal code to Rust and having problem with string<>number conversions. Here's is snippet with problem.

The Ruby version looks like this:

left_half = front_half.to_s
      (palindrome = (left_half      + left_half.reverse).to_i; basep = base11) if power.odd?
      (palindrome = (left_half.chop + left_half.reverse).to_i; basep = base)   if power.even?

The Crystal version looks like this:

palindrome, left_half = 0_u64, front_half.to_s
      palindrome = (left_half       + left_half.reverse).to_u64 if power.odd?
      palindrome = (left_half.rchop + left_half.reverse).to_u64 if power.even?
      basep      = power.odd? ? base11 : base

The Rust version looks like this:

let (mut palindrome, left_half) = (0u64, this_lo.to_string());
      if power & 1 == 1 { basep = base11; palindrome = (this_lo * base) + left_half.chars().rev().collect::<String>().parse::<u64>() }
      else              { basep = base;   palindrome = (this_lo * 10)   + left_half.chars().rev().collect::<String>().parse::<u64>() };
  1. I couldn't find a simple way to do the equivalent of chop|rchop to remove the last char of a string;

  2. I get this error for the part that tries to reverse the string, convert it back to an integer, and add it to the preceding number.

palindrome = (this_lo * 10)   + left_half.chars().rev().collect::<String>().parse::<u64>() };
   |                                                                         ^ no implementation for `u64 + std::result::Result<u64, ParseIntError>`

There's something I'm just not fundamentally understanding. :slightly_frowning_face:

Regarding the error message:

parse returns a Result since it can fail on invalid input. Since you know the input is valid you can safely unwrap the result so you’re adding u64 + u64 and not trying to add u64 + Result<u64, ...>.

1 Like

So what should the code look like?

Sorry, but I’m on mobile and have a hard time running the code but it should look something like:

palindrome = (this_lo * 10) + left_half.chars().rev().collect::<String>().parse::<u64>().unwrap()

Thank you that worked, so that problem solved. :slightly_smiling_face:

Is there a simple way to do equivalent in Ruby|Crystal: left_half.[r|chop]

Just an observation:
I spent about 6 hours searching online (stackoverflow, forum, docs, etc) last night to answer this question, and got so fed up and frustrated doing something so simple to do in Ruby|Crystal, and finally surrendered to asking this question here.

// `pop()` returns an `Option<char>` in case you have an empty string (no last character)
last_char = string_value.pop().unwrap();
// string_value is now one character shorter

I feel your pain. I suffered as you do when I first started using Rust. The problem is that I have been trained to ignore compiler error messages. In most languages the error messages seem to be designed to confuse. That's not the case with Rust.

In your example, the error message is telling you that you are trying to parse something of type Result. With a little more experience, you will immediately know that you need to have a match statement or unwrap() to get the type you expected.

Thank's for the empathy.
I actually had started with getting 20+ error messages, and whittled it down to that last issue. Maybe if it wasn't so late, or I wasn't so tired, or so just fed up, I would have figured it out by myself. Rust is good at what it's designed for, and worth learning, but damn if you don't have to be dragged through the briar patch first, so that all this stuff becomes embedded in your head. :face_with_head_bandage:

If it’s any comfort, Rust is the first programming language that I had to learn from first principles in a very long time. Returning Result, and learning how to read all the type information in general, is one of those things that takes a little time but then becomes immensely useful once you do.

Learning Rust is a bit like learning to like olives, the first tries can leave you with a bad taste, but if you try enough times you suddenly understand why people love it and you wonder how anyone would want to live a life without it.

Also, the Rust Discord channel is great for these kind of questions where you’re stuck and want some quick help.

OK, I hit another wall.

for front_half in (this_lo..next_lo-1).step_by(10) {    // d_00; d_10; d_20; ...
      let (mut palindrome, mut left_half) = (0u64, front_half.to_string());
      if power & 1 == 1 { basep = base11; palindrome = left_half.push_str(&left_half.chars().rev().collect::<String>()).parse::<u64>().unwrap() }
      else              { basep = base; left_half.pop(); palindrome = left_half.push_str(&left_half.chars().rev().collect::<String>()).parse::<u64>().unwrap() };

I'm trying to convert 2 concatenated strings into an u64 integer and get errors:

error[E0599]: no method named `parse` found for unit type `()` in the current scope
18 |       if power & 1 == 1 { basep = base11; palindrome = left_half.push_str(&left_half.chars().rev().collect::<String>()).parse::<u64>().unwrap() }
   |                                                                                                                         ^^^^^ method not found in `()`

error[E0599]: no method named `parse` found for unit type `()` in the current scope
19 |       else              { basep = base; left_half.pop(); palindrome = left_half.push_str(&left_half.chars().rev().collect::<String>()).parse::<u64>().unwrap() };
   |                                                                                                                                        ^^^^^ method not found in `()

I looked at the explain codes, but everything I tried still doesn't fix it.
I know it's gotta be something simple, but it's still not simple to me (yet). :slightly_frowning_face:

String push returns (), not the result string as you can see from the source code.

pub fn push(&mut self, ch: char) {
   // Some stuff

So how do you concatenate 2 strings and then use the result.
Please show an example.

There are a couple of ways.

    let mut foo = "abc".to_owned();
    let bar = foo.push_str("def");  // You don't need bar =.  I'm just showing the return value.
    assert_eq!((), bar);
    assert_eq!("abcdef", foo);

Another way is

let str1 = "abc";
let str2 = "def";
let qux = format!("{}{}", str1, str2);
assert_eq!("abcdef", qux);

I use it in more complex cases, e.g.,

let name = format!("P:{}", number);

This is what I ended up doing, before you posted.

if power & 1 == 1 { left_half.push_str(&left_half.chars().rev().collect::<String>()) }
else              { left_half.pop(); left_half.push_str(&left_half.chars().rev().collect::<String>()) };
let mut palindrome = left_half.parse::<u64>().unwrap();

Once I saw in the docs that, in my case, left_half is the result of the operation I just used it to convert to an integer. So that problem is solved, now to get the routine to produce the correct results all the time.

I'm somewhat curious what the intended program and/or end result are, if you have any interest in sharing.

See here:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.