How to do user input in Crystal
Asked Answered
C

3

7
puts "Input a number"
A = gets.try(&.to_i) || 0
puts "Ok now another number"
B = gets.try(&.to_i) || 0

def main 
    puts "Value of multiplication is #{A} * #{B}, Which equals = #{A * B}"
    puts "Value of addition is #{A} + #{B}, Which equals = #{A + B}"
    puts "Value of division is #{A} / #{B}, Which equals = #{A / B}"
    puts "Value of minus is #{A} - #{B}, Which equals = #{A - B}"
    puts "Value of modulus is #{A} % #{B}, Which equals = #{A % B}"
end 

main

I am wondering what the most simplest way to get user inputs from integers in Crystal would be? Similar to Ruby's gets.chomp.to_i

Colewort answered 26/7, 2018 at 6:43 Comment(0)
C
7

To get user input you have to understand how gets works. It will return a String when the user inputs something, or nil when the user didn't input anything (for example the user pressed ctrl+C).

In Ruby if you do:

x = gets.chomp.to_i

and run it, but press ctrl+C you get an ugly exception printed on the screen. Maybe that's acceptable, but it's something that Crystal won't less you pass that easily because Crystal is type safe and you will have to deal with this case. Maybe you want to print something nice to the user instead of an exception?

Ways to deal with Nil are explained here: https://crystal-lang.org/api/0.25.1/Nil.html

For example you can do:

a = gets
if a # if a is a String
  a = a.chomp.to_i # turn it into an integer
else
  exit # just silently quit the program
end

Another way is to use to_nil!, which will essentially raise an exception in case the value is nil:

a = gets.not_nil!.chomp.to_i

That's more similar to Ruby, in that you'll get an exception shown in the console when the user quits with ctrl+C. The key difference is that Crystal is letting you know (through nil) that this possibility can happen and that you should choose what to do in this case.

There are more ways to deal with this case (like the try solution suggested in other comments), depending on how terse you want the code to be.

A final alternative which is closer to Ruby is to use read_line, which will raise in case there's no input, so you can just do:

a = read_line.chomp.to_i

(though in my experiment right now it doesn't seem to be raising, I have no idea why, probably some bug...)

Chainman answered 26/7, 2018 at 13:18 Comment(1)
Thanks for the answer! Hopefully more beginners will see this here now.Colewort
M
3

This will do what you want such that the program will not continue until the user gives you a valid int. If you want to simply throw an error instead then you don't need a loop or a try-catch statement.

while true
  puts "give me a valid int:"
  begin
    i = gets.not_nil!.to_i
    break
  rescue
    puts "that wasn't a valid int."
  end
end
puts "you gave me: #{i}"
Metametabel answered 26/7, 2018 at 8:20 Comment(1)
Thanks, this is very clear and i can work with this to do other input exercises. gets.not_nil!.to_i this part especially useful for what i was trying to do!Colewort
M
1

Here has 2 ways to solve:

rough way:

print "Input a number: "
a = gets
print "now another number: "
b = gets

begin
  a = a.not_nil!.to_i
  b = b.not_nil!.to_i
  puts "Value of multiplication is #{a} * #{b}, Which equals = #{a * b}"
  puts "Value of addition is #{a} + #{b}, Which equals = #{a + b}"
  puts "Value of division is #{a} / #{b}, Which equals = #{a / b}"
  puts "Value of minus is #{a} - #{b}, Which equals = #{a - b}"
  puts "Value of modulus is #{a} % #{b}, Which equals = #{a % b}"
rescue e : Exception
  puts sprintf "error: input a or b is invalid: a = %s, b = %s", a, b
end

normal way:

def input(input : String) : Int
  value = 0
  loop do
    print input
    begin
      a = gets
      value = a.to_s.to_i  # Force convert (String | Nil) to String then Int32.
      break
    rescue
      # do nothing
    end
  end
  value
end

a = input "Input a number: "
b = input "now another number: "
puts "Value of multiplication is #{a} * #{b}, Which equals = #{a * b}"
puts "Value of addition is #{a} + #{b}, Which equals = #{a + b}"
puts "Value of division is #{a} / #{b}, Which equals = #{a / b}"
puts "Value of minus is #{a} - #{b}, Which equals = #{a - b}"
puts "Value of modulus is #{a} % #{b}, Which equals = #{a % b}"
Margretmargreta answered 26/7, 2018 at 7:1 Comment(1)
follow the examples to learn step by step: github.com/askn/crystal-by-exampleMargretmargreta

© 2022 - 2024 — McMap. All rights reserved.