提问人:Panamaniac507 提问时间:3/30/2023 最后编辑:Todd A. JacobsPanamaniac507 更新时间:3/30/2023 访问量:135
Ruby 应用程序使用 When/Case 在不应该产生 Nil 时产生 Nil
Ruby Application using When/Case yielding Nil when it shouldn't
问:
以下代码应根据任何检查的结果打印给定的三个选项之一,但事实并非如此。它产生通过 提供的任何your_message值。有人可以告诉我我的代码有什么问题吗?==
nil
gets.chomp
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
答:
在表达式中,将值与值进行比较。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
评论
大小写表达式和 Threequals
案例表达式并不像您想象的那样工作。这不仅仅是表达 if/then 条件的另一种方式。在后台,case 在将参数传递给 case 时在表达式上实现运算符,或者允许您在不传递初始参数时像一组 if 语句一样使用它。它也进行模式匹配,但这超出了这个问题的范围。===
将参数拖放到控件表达式中
当您向 case 提供参数时,例如,每个 when 语句都将使用特定于类的 threequals 而不是您认为要给出的条件来评估为针对参数的表达式。通过将参数删除到 case 中,可以很容易地解决此问题。例如:case your_message
your_message = "foo?"
case
when your_message.end_with?("?")
"bar"
end
#=> "bar"
现在,Ruby 不是有效地说(这显然会返回)而是简单地评估 when 语句是否真实。根据现有代码,这可能是获得预期行为的最简单方法。"foo?" === true
false
将 Proc、Lambda 或正则表达式与 Threequals 结合使用
或者,您可以重构 case 语句以使用 procs、lambda 甚至正则表达式,这些表达式可以匹配 threequal 比较,因为它是由类实现的。例如,请考虑以下示例,该示例利用 Proc#=== 来比较 lambda 的结果。
your_message = "foo? \n"
case your_message
when ->{ _1.strip.end_with? "?" }
"baz"
end
#=> "baz"
这基本上是将参数传递给案例(例如your_message)到 lambda 中,然后您可以在其中调用参数的方法以评估其真实性。这是一种更复杂的方法,但可能很有用。
由于正则表达式也支持 threequals 方法,因此您也可以使用这些方法:
your_message = "foo?"
case your_message
when /\?$/
"quux"
end
#=> "quux"
代码的其他问题
您还应该考虑诸如顺序依赖之类的事情。在您的示例代码中,即使没有其他问题,也永远不会匹配,因为前面的 when-语句(如果有效)会在您达到该特定比较之前根据是否存在问号返回一个值。大小写表达式不会像在其他语言中那样“失败”,因此您需要像在 if/elsif/else/end 控件表达式中一样考虑语句优先级。"I am going to work now!"
一个工作的例子
以下内容要简单得多,并且工作正常。它返回有效结果,并且不会返回 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 语句的顺序正确,并且使用正确的表达式类型进行比较,就可以让大小写表达式执行您想要的操作,但不一定是以您最初期望的方式。
评论
when your_message.eql?(your_message.upcase) && your_message.end_with?("!")
评论
.include?
和案例
的文档。your_message
true
false