具有多个变量的 Ruby case 语句

问题描述 投票:0回答:6

Ruby 有一个相当强大的

case..when..else
构造,适合您需要将条件与单个变量进行匹配的情况。在不简单嵌套
case
语句的情况下将标准与多个变量进行匹配的“规范”方法是什么?

将多个变量包装在一个数组中(如

[x, y]
)并对其进行匹配是不等价的,因为 Ruby 不会将神奇的
case ===
运算符应用于数组的 elements;该运算符仅适用于数组本身。

我将继续用社区维基的答案来回应这个问题(失败的)。

ruby pattern-matching case
6个回答
4
投票

您需要使用

if..elsif..else
,并确保要匹配的变量出现在
===
运算符的右侧(这就是
case
本质上的作用)。

例如,如果您想根据某些条件匹配

x
y

if (SomeType === x) && (1..10 === y)
  some_value
elsif (:some_symbol === x) && (11..20 === y)
  some_other_value
end

3
投票

这是一种简单的添加方式

===
:

class Array
  def ===(other)
    return false if (other.size != self.size)

    other_dup = other.dup
    all? do |e|
      e === other_dup.shift
    end
  end
end

[
  ['foo', 3],
  %w[ foo bar ],
  %w[ one ],
  []
].each do |ary|

  ary_type = case ary
  when [String, Fixnum] then "[String, Fixnum]"
  when [String, String] then "[String, String]"
  when [String] then "[String]"
  else
    "no match"
  end

  puts ary_type

end

# >> [String, Fixnum]
# >> [String, String]
# >> [String]
# >> no match

3
投票

如果这种模式在您的代码中足够常见,足以保证经济的表达,您可以自己做:

class BiPartite
  attr_reader :x, :y

  def self.[](x, y)
    BiPartite.new(x, y)
  end

  def initialize(x, y)
    @x, @y = x, y
  end

  def ===(other)
    x === other.x && y === other.y
  end
end

....

case BiPartite[x, y]
when BiPartite[SomeType, 1..10]
  puts "some_value"
when BiPartite[:some_symbol, 11..20]
  puts "some_other_value"
end

1
投票

由于 Ruby 的

when
关键字支持逗号分隔的值列表,因此您可以使用 splat
*
运算符。当然,这是假设您指的是一组位于或可能成为数组的离散值。

splat 运算符将参数列表转换为数组,如常见的

def method_missing(method, *args, &block)

不太为人所知的是,它还执行逆操作 - 将数组转换为参数列表。

所以在这种情况下,你可以这样做

passing_grades = ['b','c']
case grade
when 'a'
  puts 'great job!'
when *passing_grades
  puts 'you passed'
else
  puts 'you failed'
end

0
投票

我未经测试的解决方案是调用

.map(&:class)
,然后是
when
语句中的数组

def foo(a, b)
  case [a,b].map(&:class)
  when [Integer, Integer]
    puts "Integer"
  when [String, String]
    puts "String"
  else 
    puts "otherwise"
  end
end

0
投票

如果您正在使用字符串或可以轻松转换为字符串的内容,您可能会喜欢这个解决方案:

case [city, country].join(", ")
when "San Jose, Costa Rica"
  # ...
when "San Jose, USA"
  # ...
when "Boston, USA"
  # ...
else
  # ...
end
© www.soinside.com 2019 - 2024. All rights reserved.