在我看来,以下三个例子在逻辑上是等价的,应该产生相同的结果。
print "Enter your string: "
my_string = gets.chomp
#Example 1
my_string.include? ("j" or "J")
puts "1. Your string includes a j or J."
#Example 2
if
my_string.include? ("j" or "J")
puts "2. Your string includes a j or J."
end
#Example 3
if
my_string.include? ("j") or my_string.include? ("J")
puts "3. Your string includes a j or J."
end
以下是大写字母J的结果。
Enter your string: Jack
1. Your string includes a j or J.
3. Your string includes a j or J.
以下是小写j的结果。
Enter your string: jack
1. Your string includes a j or J.
2. Your string includes a j or J.
3. Your string includes a j or J.
由于我不明白的原因,只有示例1和3生成相同的结果。相反,在示例2中,仅评估括号中的第一项(小写j)。
但为什么呢?如果示例1完美地运行,为什么示例2仅仅因为“包含”而失败?方法嵌套在“if / end”中?
如果我们需要将代码包装在“if / elsif / end”条件中,是否有一种方法可以列出要在“include?”中评估的多个值?方法,不需要像例3那样单独写出来?如果要评估很多值,这将是乏味的 - 几乎是“反Ruby” -
换句话说,有没有办法使示例2正常工作?
答案 0 :(得分:4)
以下是每个例子中发生的事情:
此示例输出1. Your string includes a j or J.
,无论前一行如何。 my_string.include?
检查被忽略,因为它未在任何地方进行比较,因此第二行只是常规puts
。
第二个例子更有趣。 ("j" or "J")
是Ruby中的语法,它将输出第一个提供的参数,其值为true
。 "j"
求值为true,因为它不是nil或false,所以它成为第二个include?
方法的参数。 include?
区分大小写,因此会返回false
- 字符串Jack
不包含小写j
。
您可以通过运行irb
并输入1 or 2
或false and 1
等内容来尝试此操作。你很快就会看到返回第一个真正的参数(如果没有参数,则为false
。)
除了更新include?
检查以使用类似set intersections之类的内容之外,没有其它方法可以按原样进行此项工作。在检查字符之前,更简单的解决方案可能是downcase
输入。
Avdi Grimm posted a good video在Ruby中使用and
和or
。
第三个例子是在字符串上调用include?
两次,当它到达第二个调用时返回true,因此正在评估if语句。
papirtiger的回答让我思考,所以我使用以下脚本对Ripper进行了一些挖掘:
require 'ripper'
require 'pp'
expression = <<-FOO
if true
puts 'Hello'
end
FOO
pp Ripper.sexp(expression)
结果如下:
[:program,
[[:if,
[:var_ref, [:@kw, "true", [1, 3]]],
[[:command,
[:@ident, "puts", [2, 2]],
[:args_add_block,
[[:string_literal,
[:string_content, [:@tstring_content, "Hello", [2, 8]]]]],
false]]],
nil]]]
将表达式更新为以下内容后:
expression = <<-FOO
if
true
puts 'Hello'
end
FOO
这是新的输出:
[:program,
[[:if,
[:var_ref, [:@kw, "true", [2, 2]]],
[[:command,
[:@ident, "puts", [3, 2]],
[:args_add_block,
[[:string_literal,
[:string_content, [:@tstring_content, "Hello", [3, 8]]]]],
false]]],
nil]]]
看起来Ruby确实忽略了任何空格并评估下一个表达式。我没有足够的专业知识来深入挖掘,但在尝试了一些更多的例子之后(例如在if
陈述之后抛出了十几条换行符),我深信不疑。
答案 1 :(得分:3)
Ruby解释器逐行评估所有内容,并在调用方法之前首先计算参数。例如,如果您有一个读取foo(bar('test'))
的代码,那么解释器将首先评估'test'
将返回字符串test
,然后将其作为参数传递给bar
并且任何bar
返回都将传递给foo
。
让我们对每个例子应用相同的分析。
# Example 1
my_string.include? ("j" or "J")
puts "1. Your string includes a j or J."
口译员将在"j" or "J"
行评估my_string.include? ("j" or "J")
。如果您输入irb "j" or "J"
,您会看到输出为"j"
。这条线变为my_string.include?("j")
。 my_string
评估为"Jack"
,因此整个表达式变为"Jack".include?("j")
,返回false
,我们不对该信息执行任何操作,我们只是移到下一行并打印一个语句到屏幕{ {1}}。因此,无论您输入什么字符串,您都将从示例1中得到相同的答案。
让我们转到示例2.如果您在puts "1. Your string includes a j or J."
之后删除不必要的新行,则可以用更易理解的方式重写它:
if
我们尚未分析#Example 2
if my_string.include?("j" or "J")
puts "2. Your string includes a j or J."
end
,我们知道它将与my_string.include?("j" or "J")
相同,后者将返回false。因此我们得到"Jack".include?("j")
,因此if false ...
语句中的puts
语句将不会被执行,并且不会在屏幕上显示任何内容。
通过删除if
if
它会评估为if my_string.include? ("j") or my_string.include? ("J")
puts "3. Your string includes a j or J."
end
if false or true..
,因此它会打印语句。
答案 2 :(得分:1)
#Example 2
if
my_string.include? ("j" or "J")
puts "2. Your string includes a j or J."
end
在这种情况下,"j" or "J"
是一个计算结果为"j"
的表达式。你可以在irb中运行它来测试你自己。表达式始终使用左右风格的步行进行评估(请参阅http://www.cs.uml.edu/~canning/101/RLWM.pdf)。 Ruby对此有点模糊,因为最后一个方法不需要括号,所以你必须想象它们在那里
因此,"Jack"
的输入不会导致此操作,因为它不包含"j"
值得注意的是or
运算符与||
不同,如果您没有正确使用它,它可能会咬你。
它实际上更像是控制流的Perl-ism。请在此处查看Avdi的截屏视频:http://devblog.avdi.org/2014/08/26/how-to-use-rubys-english-andor-operators-without-going-nuts/
答案 3 :(得分:0)
您可以使用||
运算符代替or
来解决此问题 - 它们不可互换。例如2,尝试my_string.include?('j') || my_string.include?("J")
甚至更好,my_string.downcase.include?('j')