是否有更优雅的方法来防止Ruby中的负数?

时间:2015-07-21 04:29:13

标签: ruby negative-number

鉴于我想进行以下计算:

total = subtotal - discount

由于discount可能大于subtotal,因此代码如下:

class Calculator
  def initialize(subtotal: subtotal, discount: discount)
    @subtotal = subtotal
    @discount = discount
  end

  def total
    [subtotal - discount, 0].max
  end

  private

  def subtotal
    @subtotal
  end

  def discount
    @discount
  end
end

当看到[subtotal - discount, 0].max部分或任何类似的代码时,我经常需要停下来思考。

有更优雅的方式来处理这种计算吗?

5 个答案:

答案 0 :(得分:1)

认为我们可以扩展Numeric类?

class Numeric                                                                  
  def non_negative                                                             
    self > 0 ? self : 0                                                                      
  end                                                                          
end                                                                            

class Calculator
  def initialize(subtotal: subtotal, discount: discount)
    @subtotal = subtotal
    @discount = discount
  end

  def total
    (@subtotal - @discount).non_negative
  end
end

答案 1 :(得分:1)

我认为您的解决方案本质上是正确的,除了进行少量重构外,可能是最具可读性的。我可能会像这样稍微更改它:

  def total
    final_total = subtotal - discount
    [final_total, 0].max
  end

红宝石表达式[final_total, 0].max本质上是针对同一功能max {final_total, 0}的传统数学解决方案。区别只是符号和上下文。一旦看到此最大表达式一次或两次,就可以按以下方式读取它:“ final_total,但至少为零”。

如果您多次使用此表达式,则可以添加另一个at_least_zero方法或Shiko解决方案中的类似方法。

答案 2 :(得分:0)

简单if声明可能更容易理解:

def total
  if discount > subtotal
    0
  else
    subtotal - discount
  end
end

答案 3 :(得分:0)

为了澄清更多,我们需要在 core_ext.rb 中添加要扩展的类。文件:
1)在项目的 config \ initializers 文件夹下创建 core_ext.rb 文件。
2)如@songyy在回答中所述粘贴以下内容:

class Numeric                                                                  
  def non_negative                                                             
    self > 0 ? self : 0                                                                      
  end                                                                          
end    

参考:
https://guides.rubyonrails.org/plugins.html#extending-core-classes

答案 4 :(得分:0)

一些性能数字:

                        user     system      total        real
[i, 0.0].max        0.806408   0.001779   0.808187 (  0.810676)
0.0 if i < 0.0      0.643962   0.001077   0.645039 (  0.646368)
0.0 if i.negative?  0.625610   0.001680   0.627290 (  0.629439)

代码:

require 'benchmark'

n = 10_000_000
Benchmark.bm do |benchmark|
  benchmark.report('[value, 0.0].max'.ljust(18)) do
    n.times do |i|
      a = [-1*i, 0.0].max
    end
  end

  benchmark.report('0.0 if value < 0.0'.ljust(18)) do
    n.times do |i|
       a = 0.0 if -1*i < 0.0 
    end
  end

  benchmark.report('0.0 if value.negative?'.ljust(18)) do
    n.times do |i|
      a = 0.0 if (-1*i).negative?
    end
  end
end