使用数组的带有多个变量的 Ruby case 语句
我想比较一个 case 语句的多个变量,目前我认为覆盖数组的 case 等于运算符 (===) 是最好的方法。这是最好的方法吗?
这是一个示例用例:
def deposit_apr deposit,apr
# deposit: can be nil or 2 length Array of [nil or Float, String]
# apr: can be nil or Float
case [deposit,apr]
when [[Float,String],Float]
puts "#{deposit[0]} #{deposit[1]}, #{apr*100.0}% APR"
when [[nil,String],Float]
puts "#{apr*100.0}% APR on deposits greater than 100 #{deposit[1]}"
when [[Float,String],nil]
puts "#{deposit[0]} #{deposit[1]}"
else
puts 'N/A'
end
end
唯一的问题是数组大小写等于运算符不将大小写等于数组的元素。
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
N/A
如果我覆盖它,但我不确定如果我这样做会破坏什么:
class Array
def ===(other)
result = true
self.zip(other) {|bp,ap| result &&= bp === ap}
result
end
end
现在,一切正常:
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
656.0 rupees, 6.5% APR
我错过了什么吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我发现这个问题是因为我想在多个变量上运行
case
语句,但是,通过以下内容,得出的结论是,需要比较多个变量可能表明需要不同的方法。 (我带着这个结论回到了我自己的代码,发现即使是哈希也能帮助我编写更容易理解的代码。)今天的 Gems 使用 “无猴子补丁”作为卖点。覆盖运算符可能不是正确的方法。猴子补丁非常适合实验,但很容易出错。
此外,还有很多类型检查。在专为鸭子类型设计的语言中,这清楚地表明需要不同的方法。例如,如果我传入整数值而不是浮点数会发生什么?我们会得到“N/A”,尽管这不太可能是我们想要的。
您会注意到问题中给出的示例很难阅读。我们应该能够找到一种方法,向读者(以及作者,当他们在几个月后再次重新访问代码并不得不弄清楚发生了什么时)更清楚地表示这种逻辑。
最后,由于有多个具有关联逻辑的数字,因此似乎至少有一个 要写入的值对象类型类(
Deposit
)。为了干净起见,我假设
nil
APR 可以被视为 0.0% APR。一旦我们有了 Deposit 对象,我们就可以实现打印逻辑,而无需
case
语句。结论:如果您要比较案例陈述中的多个变量,请将其用作暗示更深层次设计问题的气味。多变量
case
可能表示有一个对象需要创建。I found this question because I was looking to run a
case
statement on multiple variables, but, going through the following, came to the conclusion that needing to compare multiple variables might suggest that a different approach is needed. (I went back to my own code with this conclusion, and found that even a Hash is helping me write code that is easier to understand.)Gems today use "no monkey patching" as a selling point. Overriding an operator is probably not the right approach. Monkey patching is great for experimentation, but it's too easy for things to go awry.
Also, there's a lot of type-checking. In a language that is designed for Duck Typing, this clearly indicates the need for a different approach. For example, what happens if I pass in integer values instead of floats? We'd get an 'N/A', even though that's not likely what we're looking for.
You'll notice that the example given in the question is difficult to read. We should be able to find a way to represent this logic more clearly to the reader (and to the writer, when they revisit the code again in a few months and have to puzzle out what's going on).
And finally, since there are multiple numbers with associated logic, it seems like there's at least one value object-type class (
Deposit
) that wants to be written.For cleanliness, I'm going to assume that a
nil
APR can be considered a 0.0% APR.Once we have our Deposit object, we can implement the print logic without needing
case
statements at all.Conclusion: If you're comparing multiple variables in a case statement, use that as a smell to suggest a deeper design issue. Multiple-variable
case
s might indicate that there's an object that wants to be created.如果您担心更改
Array
行为会破坏某些内容(当然这是一个合理的担心),那么只需将修改后的运算符放入 Array 的子类中即可。If you are worried about breaking something by changing
Array
behavior, and certainly that's a reasonable worry, then just put your revised operator in a subclass of Array.这绝对不是最好的方法。更重要的是 - 您不应该重新定义标准类的方法,因为核心功能可能依赖于它 - 然后享受调试的乐趣。
防御风格很好(有很多类型检查等等),但它通常会损害性能和可读性。
如果您知道除了一堆浮点数和字符串之外不会将任何其他内容传递给该方法 - 为什么您需要所有这些检查?
IMO 使用异常捕获并修复问题的根源,不要尝试在中间的某个地方修复问题
it's definitely not the best way. even more - you should not redefine methods of standart classes as core functionality may depend on it - have fun debugging then.
defensive style is nice(with lot of type checks and whatnot) but it usually hurts performance and readability.
if you know that you will not pass anything else than bunch of floats and strings to that method - why do you need all those checks for?
IMO use exception catching and fix the source of problem, don't try to fix the problem somewhere in the middle