I just finished a Rosetta Code task translation from Crystal to Rust and thought I’d share some observations.

Even for this simple example, Rust caused me all kinds of tears and pain to learn how to do string>number and number>string conversions. CrystalRuby is so much simpler. (See: https://users.rustlang.org/t/numberstringbacktostringreversenumber/51913/15)

Rust is a bit faster, on an applestoapples comparison doing this algorithm.

Rust raw executable is larger, but stripped is almost half the size.

Conclusion: If you really, Really, REALLY need optimal speed, use Rust. If you want to get stuff done quickly, and still have time to live your life, use Crystal. YMMV!
Hear are some statistics:
 speed  exe (raw) bytes  exe (stripped) bytes
Crystal  25.40s  886,520  434,600
Rust  20.06s  1,373,528  268,576
Compiled as:
Crystal:
$ crystal build release palindromicgapfuls.cr
Rust:
$ rustc C optlevel=3 C targetcpu=native C codegenunits=1 C lto palindromicgapuls.rs
Here’s the Crystal code:
def palindromicgapfuls(digit, count, keep)
skipped = 0 # initial count of skipped values
to_skip = count  keep # count of unwanted values to skip
gapfuls = [] of UInt64 # array of palindromic gapfuls
nn = digit * 11 # digit gapful divisor: 11, 22,...88, 99
(2..).select do power
base = 10_u64**(power >> 1) # value of middle digit position: 10..
base11 = base * 11 # value of middle two digits positions: 110..
this_lo = base * digit # starting half for this digit: 10.. to 90..
next_lo = base * (digit + 1) # starting half for next digit: 20.. to 100..
this_lo.step(to: next_lo  1, by: 10) do front_half # d_00; d_10; d_20; ...
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
10.times do
(gapfuls << palindrome if (skipped += 1) > to_skip) if palindrome.divisible_by?(nn)
palindrome += basep
end
return gapfuls[0...keep] unless gapfuls.size < keep
end
end
end
start = Time.monotonic
count, keep = 20, 20
puts "First 20 palindromic gapful numbers ending with:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
count, keep = 100, 15
puts "\nLast 15 of first 100 palindromic gapful numbers ending in:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
count, keep = 1_000, 10
puts "\nLast 10 of first 1000 palindromic gapful numbers ending in:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
count, keep = 100_000, 1
puts "\n100,000th palindromic gapful number ending with:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
count, keep = 1_000_000, 1
puts "\n1,000,000th palindromic gapful number ending with:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
count, keep = 10_000_000, 1
puts "\n10,000,000th palindromic gapful number ending with:"
1.upto(9) { digit puts "#{digit} : #{palindromicgapfuls(digit, count, keep)}" }
puts (Time.monotonic  start).total_seconds
Here’s the Rust code:
fn palindromicgapfuls(digit: u64, count: u64, keep: usize) > Vec<u64> {
let mut skipped = 0u64; // initial count of skipped values
let to_skip = count  keep as u64; // count of unwanted values to skip
let mut gapfuls: Vec<u64> = vec![]; // array of palindromic gapfuls
let nn = digit * 11; // digit gapful divisor: 11, 22,...88, 99
let (mut power, mut base) = (1, 1u64);
loop { power += 1;
if power & 1 == 0 { base *= 10 }; // value of middle digit position: 10..
let base11 = base * 11; // value of middle two digits positions: 110..
let this_lo = base * digit; // starting half for this digit: 10.. to 90..
let next_lo = base * (digit + 1); // starting half for next digit: 20.. to 100..
for front_half in (this_lo..next_lo).step_by(10) { // d_00; d_10; d_20; ...
let (mut left_half, mut basep) = (front_half.to_string(), 0);
let right_half = left_half.chars().rev().collect::<String>();
if power & 1 == 1 { basep = base11; left_half.push_str(&right_half) }
else { basep = base; left_half.pop(); left_half.push_str(&right_half) };
let mut palindrome = left_half.parse::<u64>().unwrap();
for _ in 0..10 {
if palindrome % nn == 0 { skipped += 1; if skipped > to_skip { gapfuls.push(palindrome) } };
palindrome += basep;
}
if gapfuls.len() >= keep { return gapfuls[0..keep].to_vec() };
}
}
}
fn main() {
let t = std::time::Instant::now();
let (count, keep) = (20, 20);
println!("First 20 palindromic gapful numbers ending with:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
let (count, keep) = (100, 15);
println!("\nLast 15 of first 100 palindromic gapful numbers ending in:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
let (count, keep) = (1_000, 10);
println!("\nLast 10 of first 1000 palindromic gapful numbers ending in:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
let (count, keep) = (100_000, 1);
println!("\n100,000th palindromic gapful number ending with:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
let (count, keep) = (1_000_000, 1);
println!("\n1,000,000th palindromic gapful number ending with:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
let (count, keep) = (10_000_000, 1);
println!("\n10,000,000th palindromic gapful number ending with:");
for digit in 1..10 { println!("{} : {:?}", digit, palindromicgapfuls(digit, count, keep)); }
println!("{:?}", t.elapsed())
}
Here is the full code and output on Rosettacode.org
Crystal:
Rust: