如何修复Ruby中的“将字符串转换为整数”错误

时间:2019-11-02 13:31:51

标签: ruby-on-rails

我需要根据各种费率确定运费。

过去5个小时,我尝试了大杂烩。 如果我应该使用.to_s .to_f,则我尝试并这样做不正确。

if (weight < 2)

     rate = 0.10

   elsif ((weight >= 2) or (weight < 10))

     rate = 0.20

   elsif ((weight >= 10) or (weight < 40))

     rate = 0.30

   elsif ((weight >= 40) or (weight < 70))

     rate = 0.50

   elsif ((weight >= 70) or (weight < 100))

     rate = 0.75

   else (weight >= 100)

     rate = 0.90

end

rate = rate.to_i

ship_cost = weight * price * rate

ship_cost = ship_cost.to_i

应用费率后,结果应该显示出运输成本。我不断遇到“字符串到整数”错误。

2 个答案:

答案 0 :(得分:2)

问题是乘法中的一个或多个变量是一个字符串,这会导致您得到TypeError错误,例如:

'a' * 'b' #  '*': no implicit conversion of String into Integer (TypeError)

如果要抑制该错误,可以将其手动转换为整数或浮点数。这意味着如果字符串没有数字表示,它将返回0:

'asd'.to_i  # 0
'1'.to_i.   # 1
'-9.9'.to_i # -9
'-9.9'.to_f # -9.9

或者,您可以使用“字典”来处理rate分配,该字典包含最小值和最大值weight可以返回X。创建一个从最小到最大的范围,并询问它是否包含权重值,您可以为其分配值:

dict = {
  [-Float::INFINITY, 2]  => 0.10,
  [2, 10]                => 0.20,
  [10, 40]               => 0.30,
  [40, 70]               => 0.50,
  [70, 100]              => 0.75,
  [100, Float::INFINITY] => 0.90
}

p dict.find { |(start, finish), _| (start...finish).include?(-42.12) }.last # 0.1
p dict.find { |(start, finish), _| (start...finish).include?(0) }.last      # 0.1
p dict.find { |(start, finish), _| (start...finish).include?(1) }.last      # 0.1
p dict.find { |(start, finish), _| (start...finish).include?(23) }.last     # 0.3
p dict.find { |(start, finish), _| (start...finish).include?(101) }.last    # 0.9

答案 1 :(得分:1)

一个不太冗长和习惯用法更正确的解决方案是使用带有范围的case语句:

def shipping_rate(weight)
  case weight
  when 0...2
     0.10
  when 2...10
     0.20
  when 10...40
     0.30
  when 40...70
     0.50
  when 70...100
     0.75
  when 100...Float::INFINITY
     0.90
  end
end

使用...声明范围会排除最终值。 (40...70).cover?(70) == false这样。这样我们就可以避免重叠问题。

require "minitest/autorun"
class TestShippingRate < Minitest::Test
  def test_correct_rate
    assert_equal 0.10, shipping_rate(1)
    assert_equal 0.20, shipping_rate(3)
    assert_equal 0.30, shipping_rate(39)
    assert_equal 0.50, shipping_rate(40)
    assert_equal 0.75, shipping_rate(70)
    assert_equal 0.90, shipping_rate(101)
  end
end

# Finished in 0.002255s, 443.3896 runs/s, 2660.3374 assertions/s.
# 1 runs, 6 assertions, 0 failures, 0 errors, 0 skips

如果您想使用塞巴斯蒂安·帕尔玛(Sebastian Palma)建议的字典,则可以使用带有键范围的哈希来代替:

def shipping_rate(weight)
  {
    0...2 => 0.10,
    2...10 => 0.20,
    10...40 => 0.30,
    40...70 => 0.50,
    70...100 => 0.75,
    100...Float::INFINITY => 0.90
  }.find { |k, v| break v if k.cover? weight }
end

使用case稍微灵活一点,尽管您可以添加一个else条件或处理字符串参数:

def shipping_rate(weight)
  case weight
  when 0...2
     0.10
  when 2...10
     0.20
  when 10...40
     0.30
  when 40...70
     0.50
  when 70...100
     0.75
  when 100...Float::INFINITY
     0.90
  # I'm not saying this is a good idea as the conversion should happen
  # upstream. Its just an example of what you can do
  when String
     shipping_rate(weight.to_f) # recursion
  else 
     raise "Oh noes. This should not happen."
  end
end