Ruby应用程序使用When/Case在不应该使用时产生Nil

57hvy0tb  于 2023-04-05  发布在  Ruby
关注(0)|答案(2)|浏览(163)

下面的代码应该根据==检查的结果打印出三个选项中的一个,但是它没有。它对通过gets.chomp提供的 your_message 的任何值都产生nil。有人能告诉我我的代码有什么问题吗?

def stupid_coach(your_message)
  case your_message
  when your_message == your_message.include?("?")
    p "Silly question, get dressed and go to work!"
  when !your_message == your_message.include?("?")
    p "I don't care, get dressed and go to work!"
  when your_message == "I am going to work now!"
    exit
  end
end
rt4zxlrg

rt4zxlrg1#

大小写表达式和Threequals

case表达式并不像你想象的那样工作。它不仅仅是表达if/then条件的另一种方式。在幕后,case在向case传递参数时在表达式上实现===运算符,或者如果你不传递初始参数,它允许你像一组if语句一样使用它。它也可以进行模式匹配,但这超出了这个问题的范围。

将参数删除到控制表达式

当你为case提供一个参数时,比如case your_message,那么每个when-statement将被计算为一个 expression,并使用类特定的threequals而不是你认为你给它的条件。这很容易通过将参数删除到case来解决。例如:

your_message = "foo?"

case
when your_message.end_with?("?")
  "bar"
end

#=> "bar"

现在,Ruby不再有效地说"foo?" === true(这显然会返回false),而是简单地评估when-statement是否为真。基于您现有的代码,这可能是获得预期行为的最简单方法。

使用Proc、Lambda或Regexp和Threequals

或者,您可以重新构造case语句,以使用procs、lambdas甚至正则表达式来匹配threequal比较,因为它是由类实现的。例如,考虑以下示例,该示例利用Proc#===来比较lambda的结果。

your_message = "foo? \n"

case your_message
when ->{ _1.strip.end_with? "?" }
  "baz"
end

#=> "baz"

这基本上是将参数传递给case(例如 your_message)到lambda中,然后您可以在其中调用参数的方法来评估其真实性。这是一种更复杂的方法,但可能很有用。
因为正则表达式也支持threequals方法,你也可以使用它们:

your_message = "foo?"

case your_message
when /\?$/
  "quux"
end

#=> "quux"

代码的其他问题

在示例代码中,即使没有其他问题,"I am going to work now!"也永远不会被匹配,因为前面的when-statements(如果工作)将根据在进行特定比较之前是否存在问号返回一个值。大小写表达式不会像其他语言那样“失败”,所以你需要像在if/elsif/else/end控制表达式中一样考虑语句优先级。

工作示例

下面的代码要简单得多,并且运行良好。它返回有效的结果,并且不会返回nil。它 * 确实 * 假设 your_message 可以#respond_to?(:strip),但是如果你愿意,你可以进一步调整代码。

def stupid_coach your_message
    case your_message.strip
    when "I am going to work now!"
      "This works when checked before matching for '?'."
    when /\?$/
      "Silly question, get dressed and go to work!"
    else
      "I don't care, get dressed and go to work!"
    end 
end

你可以用一个样本输入数组来测试它,结果对我来说似乎是有效的,但是如果你认为有一个极端的情况,你当然可以用它来测试其他的String值。

["Foo?", "Bar.", "I am going to work now!"]
  .map { stupid_coach _1 }

#=> 
["Silly question, get dressed and go to work!",
 "I don't care, get dressed and go to work!",
 "This can match if checked before mactching for '?'."]

执行样本的顺序并不重要。如果重新排序测试数组,仍然可以得到正确的结果。只要when-statements的顺序正确,并且使用正确类型的表达式进行比较,就可以让case表达式做你想做的事情-只是不一定是你最初期望的方式。

xuo3flqw

xuo3flqw2#

case表达式中,when将值与一个值进行比较。
在本例中,您将your_message(可能是一个字符串)与布尔值进行比较。
考虑一个非常简单的例子:

irb(main):001:1* case "hello"
irb(main):002:1* when true
irb(main):003:1*   puts "foo"
irb(main):004:1* else
irb(main):005:1*   puts "bar"
irb(main):006:0> end
bar
=> nil

您可以使用正则表达式或匹配字符串。

def stupid_coach(your_message)
    case your_message
    when "I am going to work now!"
        exit
    when /\?/
        p "Silly question, get dressed and go to work!"
    else
        p "I don't care, get dressed and go to work!"
    end
end

虽然我不确定您是否真的希望像代码遇到exit时那样退出程序,并且方法本身将返回nil
如果你希望它返回字符串而不是打印它们:

def stupid_coach(your_message)
    case your_message
    when "I am going to work now!"
        exit
    when /\?/
        "Silly question, get dressed and go to work!"
    else
        "I don't care, get dressed and go to work!"
    end
end

相关问题