使用数组的具有多个变量的 Ruby case 语句

标签 ruby arrays case equals

我想比较一个 case 语句的多个变量,目前正在考虑为 Array 覆盖 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

唯一的问题是 Array case equals operator 不对 Array 的元素应用 case equal。

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

我错过了什么吗?

最佳答案

我发现这个问题是因为我想运行一个 case关于多个变量的陈述,但是通过以下内容得出的结论是,需要比较多个变量可能表明需要采用不同的方法。 (我带着这个结论回到我自己的代码,发现即使是一个 Hash 也在帮助我写出更容易理解的代码。)

今天使用的 gem "no monkey patching" as a selling point .覆盖运算符可能不是正确的方法。 Monkey 补丁非常适合实验,但也很容易出错。

此外,还有很多类型检查。在为 Duck Typing 设计的语言中,这清楚地表明需要一种不同的方法。例如,如果我传入整数值而不是 float ,会发生什么情况?我们会得到一个“N/A”,即使这不太可能是我们正在寻找的。

您会注意到问题中给出的示例难以阅读。我们应该能够找到一种方法向读者(以及作者,当他们在几个月后再次访问代码并且不得不弄清楚到底发生了什么时)更清楚地表示这种逻辑。

最后,由于有多个数字具有关联逻辑,因此似乎至少有一个 value object。 - 要写入的类 ( Deposit)。

为了清洁起见,我假设一个 nil APR 可视为 0.0% APR。

class Deposit
  def initialize(amount, unit='USD', options={})
    @amount = amount.to_f # `nil` => 0.0
    @unit   = unit.to_s   # Example assumes unit is always present
    @apr    = options.fetch(:apr, 0.0).to_f # `apr: nil` => 0.0
  end
end

一旦我们有了 Deposit 对象,我们就可以实现打印逻辑而不需要 case完全没有陈述。

class Deposit

  # ... lines omitted

  def to_s
    string = "#{@amount} #{@unit}"
    string << ", #{@apr * 100.0}% APR" if @apr > 0.0
    string
  end
end

d = Deposit.new(656.00, 'rupees', apr: 0.065)
d.to_s
# => "656.0 rupees, 6.5% APR"

e = Deposit.new(100, 'USD', apr: nil)
e.to_s
# => "100.0 USD"

f = Deposit.new(100, 'USD')
f.to_s
# => "100.0 USD"

结论:如果您在案例陈述中比较多个变量,请将其用作气味来暗示更深层次的设计问题。多变量 case s 可能表示有一个对象要创建。

关于使用数组的具有多个变量的 Ruby case 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4838808/

相关文章:

ruby-on-rails - 使用 Windows 安装 json 1.8.2 时出错

ruby-on-rails - 如何在 RoR 中返回我当前的时区?

c++ - 在 C++ 中创建一个 json 数组

sql - CASE WHEN...INTO - 存储过程

python - Rails 应用程序中 Ruby 子外壳中的引用文件

ruby - 在 Ruby 安装 (1.9.2) 期间遇到 RVM 问题

javascript - 除非已经写入事件,否则如何使用 document.write() 写入事件?

javascript - 更改 typescript 中数组的类型

sql - Oracle sql 查询,将字段与 CASE 部分连接起来

mysql - SQL 中子查询中 CASE WHEN EXIST 的奇怪行为 (MySQL 5.5)