问题
Given that I'd like to do the following calculation:
total = subtotal - discount
Because discount
might be greater than subtotal
, there is code like the following:
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
When seeing the [subtotal - discount, 0].max
part or any similar code, I often have to pause and think.
Are there more elegant ways to handle this kind of calculation?
回答1:
I think your solution is essentially correct, and probably the most readable besides a small refactor. I might change it slightly like so:
def total
final_total = subtotal - discount
[final_total, 0].max
end
The ruby expression [final_total, 0].max
is essentially the traditional solution in mathematics for the same function: max {final_total, 0}
. The difference is just notation and context. Once you see this max expression once or twice you can read it as follows: "final_total, but at least zero".
Perhaps if you use this expression more than once you can add another at_least_zero
method or something like in Shiko's solution.
回答2:
Thinking we can extend the Numeric
class?
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
回答3:
A plain if
statement might be easier to understand:
def total
if discount > subtotal
0
else
subtotal - discount
end
end
回答4:
Just to clarify more, we need to add classes to be extended in core_ext.rb . file :
1) Create core_ext.rb file under config\initializers folder in your project.
2) Paste below as mentioned by @songyy in his answer:
class Numeric
def non_negative
self > 0 ? self : 0
end
end
Reference:
https://guides.rubyonrails.org/plugins.html#extending-core-classes
来源:https://stackoverflow.com/questions/31530404/are-there-more-elegant-ways-to-prevent-negative-numbers-in-ruby