【问题标题】:Case statement with multiple values in each 'when' block每个 'when' 块中具有多个值的 case 语句
【发布时间】:2012-04-29 03:33:23
【问题描述】:

我可以描述我正在寻找的最佳方式是向您展示我迄今为止尝试过的失败代码:

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

我有大约 4 或 5 种不同的 when 情况,它们应该由大约 50 种不同的可能值 car 触发。有没有办法用case 块来做到这一点,还是我应该尝试一个巨大的if 块?

【问题讨论】:

    标签: ruby-on-rails ruby syntax switch-statement


    【解决方案1】:

    case 语句中,, 等效于if 语句中的||

    case car
       when 'toyota', 'lexus'
          # code
    end
    

    Some other things you can do with a Ruby case statement

    【讨论】:

    • This link 对 Ruby 中的 case 语句有更好的总结(它还包括 regexp 和 splat 语法的示例)。
    • 我不知道为什么,但是这种奇怪的情况发生了:当我写这个时:when "toyota", "lexus",我得到:unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError)。但是,当我写这个:when "toyota","lexus" 时,它起作用了。唯一的区别是逗号后面有一个空格。
    • @FurkanAyhan 这很奇怪。我继续前进,tested the code 只是为了确保它确实有效。我的猜测是您的代码中还有其他一些事情会导致这样的错误。您是否有可能忘记在某处或类似的地方关闭一个字符串?
    • 好吧,这行得通,但是由于 ruby​​ 专注于程序员的易用性,我想知道为什么它不支持标准 ||或“或”?这有点令人困惑
    • Ruby 在这里不支持or||,因为when 在其右侧采用一系列逗号分隔的表达式,而不是单个标识符。正因为如此,如果你有when a or b,不清楚是否将其视为when a, bwhen (a or b) 的等价物,后者在将其放入when 之前首先评估表达式a or b。如果语言具有根据上下文改变行为的标记,那么您将无法在 when 的右侧使用真正的 or 表达式,这更令人惊讶且更不容易处理。
    【解决方案2】:

    您可以利用 ruby​​ 的“splat”或扁平化语法。

    这使得when 子句过度生长——如果我理解正确的话,每个分支你有大约 10 个值要测试——在我看来更具可读性。此外,您可以修改值以在运行时进行测试。例如:

    honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
    toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
    ...
    
    if include_concept_cars
      honda += ['ev-ster', 'concept c', 'concept s', ...]
      ...
    end
    
    case car
    when *toyota
      # Do something for Toyota cars
    when *honda
      # Do something for Honda cars
    ...
    end
    

    另一种常见的方法是使用散列作为调度表,每个值的键为car,值是封装您希望执行的代码的一些可调用对象。

    【讨论】:

    • 这就是我最终使用的,虽然我觉得拿走某人的复选标记很糟糕:D
    • when 行的出色解决方案。感谢分享。
    【解决方案3】:

    记住switch/case(case/when等)只是比较。我喜欢这种情况下的官方答案,用于简单的或字符串列表比较,但对于更奇特的条件/匹配逻辑,

    case true
      when ['honda', 'acura'].include?(car)
        # do something
      when (condition1 && (condition2 || condition3))
        # do  something different
      else
        # do something else
    end
    

    【讨论】:

      【解决方案4】:

      另一种将逻辑放入数据的好方法是这样的:

      # Initialization.
      CAR_TYPES = {
        foo_type: ['honda', 'acura', 'mercedes'],
        bar_type: ['toyota', 'lexus']
        # More...
      }
      @type_for_name = {}
      CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }
      
      case @type_for_name[car]
      when :foo_type
        # do foo things
      when :bar_type
        # do bar things
      end
      

      【讨论】:

      • 我并不是要粗鲁,但我投了反对票,因为这在时间和空间上效率都较低。它也比其他两个答案更复杂且可读性更低。使用这种方法有什么好处?
      • 它将您的整个分类放在一个对象中。您现在可以对该对象进行操作,例如将其序列化并将其发送给其他人以解释您的逻辑,或者将其存储在数据库中并允许人们对其进行编辑。 (当新车型问世时,逻辑很快就会改变,对吧?)您可能会查找“table-driven”。
      • YAGNI(“你不需要它”)可能适用于此。该设计为将来可能存在但尚不存在的场景牺牲了时间/空间效率和可读性。现在付出了代价,但可能永远也得不到回报。
      【解决方案5】:

      你可以做这样的事情(受@pilcrow 的回答启发):

      honda  = %w[honda acura civic element fit ...]
      toyota = %w[toyota lexus tercel rx yaris ...]
      
      honda += %w[ev_ster concept_c concept_s ...] if include_concept_cars
      
      case car
      when *toyota
        # Do something for Toyota cars
      when *honda
        # Do something for Honda cars
      ...
      end
      

      【讨论】:

        【解决方案6】:

        在 case 语句中,相当于 if 语句中的 &&。

        案例编码_语言 当'ror' && 'javascript' # 代码 结束

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-08-17
          • 1970-01-01
          • 1970-01-01
          • 2015-09-17
          • 1970-01-01
          相关资源
          最近更新 更多