如何在 Crystal 中进行用户输入

How to do user input in Crystal

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

我想知道从 Crystal 中的整数获取用户输入的最简单方法是什么?类似于 Ruby 的 gets.chomp.to_i

这里有2种方法可以解决:

粗略的方法:

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

正常方式:

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

这会做你想做的,这样程序就不会继续,直到用户给你一个有效的整数。如果您只想抛出错误,则不需要循环或 try-catch 语句。

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

要获得用户输入,您必须了解 gets 的工作原理。它会 return 一个 String 当用户输入一些东西时,或者 nil 当用户没有输入任何东西时(例如用户按下 ctrl+C)。

在 Ruby 如果你这样做:

x = gets.chomp.to_i

和 运行 它,但是按 ctrl+C 你会在屏幕上打印出一个丑陋的异常。也许这是可以接受的,但 Crystal 不会让你轻易通过,因为 Crystal 是类型安全的,你将不得不处理这种情况。也许您想向用户打印一些好东西而不是异常?

处理Nil的方法在这里解释:https://crystal-lang.org/api/0.25.1/Nil.html

例如你可以这样做:

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

另一种方法是使用 to_nil!,如果值为 nil:

,这实际上会引发异常
a = gets.not_nil!.chomp.to_i

这与 Ruby 更相似,因为当用户使用 ctrl+C 退出时,控制台会显示异常。 主要区别在于 Crystal 让您知道(通过 nil)这种可能性可能发生,您应该选择在这种情况下做什么。

有更多方法可以处理这种情况(如其他评论中建议的 try 解决方案),具体取决于您希望代码的简洁程度。

最后一个更接近 Ruby 的替代方法是使用 read_line,如果没有输入,它会引发,所以你可以这样做:

a = read_line.chomp.to_i

(虽然在我的实验中它现在似乎没有提高,我不知道为什么,可能是一些错误...)