为什么在将用户输入转换为整数时 Crystal 中需要 .to_s 方法?
Why is the .to_s method needed in Crystal when converting user input to an integer?
我刚开始 Crystal,但我 运行 遇到了一些我不明白的事情。我写了一个简单的程序来演示,它从控制台获取一个数字并添加一个。
Ruby
# Add one program.
puts "Enter a number."
number = gets
number = number.to_i
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
Crystal
# Add one program.
puts "Enter a number."
number = gets
number = number.to_s.to_i # Why is to_s needed?
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
如您所见,程序几乎相同,但是,在 crystal 中,我必须从控制台获取输入并将其转换为字符串,然后才能将其转换为整数。
我想知道的是:
- crystal 中的 gets 返回了什么?
- 有没有不用链接方法的另一种方法?
这似乎是一个基本问题,但 crystal 还处于早期阶段,而且文档也很少。
错误
Error in example.cr:6: undefined method 'to_i' for Nil (compile-time type is (String | Nil)) (did you mean 'to_s'?)
number = number.to_i # Why is to_s needed?
^~~~
================================================================================
Nil trace:
example.cr:4
number = gets
^~~~~~
example.cr:4
number = gets
^~~~
/usr/share/crystal/src/kernel.cr:105
def gets(*args, **options)
/usr/share/crystal/src/kernel.cr:105
def gets(*args, **options)
^
/usr/share/crystal/src/kernel.cr:106
STDIN.gets(*args, **options)
^~~~
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
^
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
^~~~
/usr/share/crystal/src/io.cr:575
gets '\n', chomp: chomp
^~~~
/usr/share/crystal/src/io.cr:604
def gets(delimiter : Char, chomp = false) : String?
^~~~
/usr/share/crystal/src/io.cr:605
gets delimiter, Int32::MAX, chomp: chomp
^~~~
/usr/share/crystal/src/io.cr:618
def gets(delimiter : Char, limit : Int, chomp = false) : String?
^~~~
/usr/share/crystal/src/io.cr:619
raise ArgumentError.new "Negative limit" if limit < 0
^
/usr/share/crystal/src/io.cr:632
if ascii && !decoder && (peek = self.peek)
^
/usr/share/crystal/src/io.cr:633
if peek.empty?
^
/usr/share/crystal/src/io.cr:634
nil
^
在大多数情况下,gets
将 return 一个字符串,但它也可能 returns nil
。
这在 Ruby 中不是问题,因为在您的示例中,您将在运行时 nil
returned,即使您有,也有 NilClass#to_i
在 Ruby 中总是 returns 0
.
但是 Crystal 编译器会预先检查对象类型,因此确保您的代码可以处理所有可能的 return 类型。不幸的是,在 Crystal 中,Nil
上还没有 to_i
方法,因此您会得到编译器错误:
undefined method 'to_i' for Nil (compile-time type is (String | Nil))
当运行任一程序时,尝试将 Ctrl+D (EOF) 作为输入。程序是否按预期运行?
Crystal 让您处理方法可能 return 的所有可能类型,从而保护您免受此类编程错误的侵害。例如,该程序的更正确版本可能是:
print "Enter a number: "
number = gets.try &.to_i?
if number
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
else
puts "Please enter a valid number"
end
注意:String#to_i?
returns nil
当转换失败时,而不是像 String#to_i
那样引发异常。
我刚开始 Crystal,但我 运行 遇到了一些我不明白的事情。我写了一个简单的程序来演示,它从控制台获取一个数字并添加一个。
Ruby
# Add one program.
puts "Enter a number."
number = gets
number = number.to_i
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
Crystal
# Add one program.
puts "Enter a number."
number = gets
number = number.to_s.to_i # Why is to_s needed?
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
如您所见,程序几乎相同,但是,在 crystal 中,我必须从控制台获取输入并将其转换为字符串,然后才能将其转换为整数。
我想知道的是:
- crystal 中的 gets 返回了什么?
- 有没有不用链接方法的另一种方法?
这似乎是一个基本问题,但 crystal 还处于早期阶段,而且文档也很少。
错误
Error in example.cr:6: undefined method 'to_i' for Nil (compile-time type is (String | Nil)) (did you mean 'to_s'?)
number = number.to_i # Why is to_s needed?
^~~~
================================================================================
Nil trace:
example.cr:4
number = gets
^~~~~~
example.cr:4
number = gets
^~~~
/usr/share/crystal/src/kernel.cr:105
def gets(*args, **options)
/usr/share/crystal/src/kernel.cr:105
def gets(*args, **options)
^
/usr/share/crystal/src/kernel.cr:106
STDIN.gets(*args, **options)
^~~~
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
^
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
/usr/share/crystal/src/io.cr:574
def gets(chomp = true) : String?
^~~~
/usr/share/crystal/src/io.cr:575
gets '\n', chomp: chomp
^~~~
/usr/share/crystal/src/io.cr:604
def gets(delimiter : Char, chomp = false) : String?
^~~~
/usr/share/crystal/src/io.cr:605
gets delimiter, Int32::MAX, chomp: chomp
^~~~
/usr/share/crystal/src/io.cr:618
def gets(delimiter : Char, limit : Int, chomp = false) : String?
^~~~
/usr/share/crystal/src/io.cr:619
raise ArgumentError.new "Negative limit" if limit < 0
^
/usr/share/crystal/src/io.cr:632
if ascii && !decoder && (peek = self.peek)
^
/usr/share/crystal/src/io.cr:633
if peek.empty?
^
/usr/share/crystal/src/io.cr:634
nil
^
在大多数情况下,gets
将 return 一个字符串,但它也可能 returns nil
。
这在 Ruby 中不是问题,因为在您的示例中,您将在运行时 nil
returned,即使您有,也有 NilClass#to_i
在 Ruby 中总是 returns 0
.
但是 Crystal 编译器会预先检查对象类型,因此确保您的代码可以处理所有可能的 return 类型。不幸的是,在 Crystal 中,Nil
上还没有 to_i
方法,因此您会得到编译器错误:
undefined method 'to_i' for Nil (compile-time type is (String | Nil))
当运行任一程序时,尝试将 Ctrl+D (EOF) 作为输入。程序是否按预期运行?
Crystal 让您处理方法可能 return 的所有可能类型,从而保护您免受此类编程错误的侵害。例如,该程序的更正确版本可能是:
print "Enter a number: "
number = gets.try &.to_i?
if number
puts "You entered #{number}. #{number} + 1 = #{number + 1}"
else
puts "Please enter a valid number"
end
注意:String#to_i?
returns nil
当转换失败时,而不是像 String#to_i
那样引发异常。