На самом деле в вашем вопросе есть несколько разных вопросов.
Первый в заголовке:
Могу ли я использовать сравнение между двумя переменными внутри оператора Ruby case?
И ответ на этот вопрос "Да, конечно, почему бы вам не?" Вы можете использовать любое Ruby выражение .
Хорошо, хорошо, если мы хотим быть по-настоящему педантичными c, ответ будет "Нет" по двум причинам:
- Вы не можете сравнивать переменные, вы можете только сравнивать объекты, а переменные не являются объектами.
- Ruby не имеет оператора
case
, только case
выражение . (На самом деле, Ruby вообще не имеет операторов .)
(Это может звучать слишком педантично c, но понимание различия между переменными и объектами фундаментальный не только в Ruby, но и в программировании в целом , как и разница между выражениями и операторами.)
Ваш следующий вопрос: почему вы получаете nil
. Ответ заключается в том, что последнее выражение в вашем коде -
puts end_game_message(21, 15)
Итак, ваш код оценивается как возвращаемое значение Kernel#puts
, а Kernel#puts
определено как всегда return nil
.
Вопрос, который, я думаю, вы действительно задаете, но на самом деле не в вашем вопросе: «Почему выражение case
не работает так, как я думаю? делает? "
Вам просто нужно запомнить, как вычисляется выражение case
. Существуют две разные формы выражения case
. (См. раздел 11.5.2.2.4 case
выражение ) спецификации языка ISO Ruby , например.
Более простая форма - это то, что Спецификация языка ISO Ruby вызывает case
выражение без выражения , которое выглядит следующим образом:
case # Look ma, no expression
when bar then :bar
when baz then :baz
else :qux
end
И оценивается следующим образом:
if bar then :bar
elsif baz then :baz
else :qux
end
Другой формой является case
-выражение с выражением
case foo # In this case, there is an expression here
when bar then :bar
when baz then :baz
else :qux
end
, которое оценивается так:
if bar === foo then :bar
elsif baz === foo then :baz
else :qux
end
В вашем случае , вы используете case
-expression-with-expression , поэтому ваше выражение case
оценивается так:
if (player_score == 21) === player_score
message = "Black Jack!"
elsif (player_score > bank_score) === player_score
message = "You win!"
elsif (player_score > 21) === player_score
message = "You lose!"
elsif (player_score < bank_score) === player_score
message = "You lose"
elsif (player_score == bank_score) === player_score
message = "Push"
end
С player_score == 21
, player_score > bank_score
, player_score > 21
, player_score < bank_score
и player_score == bank_score
оцениваются как true
или false
, а player_score
- это число, все ветви в вашем выражении case
фактически проверяют что-то вроде этого:
some_boolean === some_number
Что никогда true!
Итак, как мы можем это исправить?
Простейшим решением было бы использование case
-expression-withou Вместо этого t-выражение , и для этого единственное, что нам нужно сделать, - это удалить выражение после case
:
case
when player_score == 21
message = "Black Jack!"
when player_score > bank_score
message = "You win!"
when player_score > 21
message = "You lose!"
when player_score < bank_score
message = "You lose"
when player_score == bank_score
message = "Push"
end
. Это будет оценено следующим образом:
if player_score == 21
message = "Black Jack!"
elsif player_score > bank_score
message = "You win!"
elsif player_score > 21
message = "You lose!"
elsif player_score < bank_score
message = "You lose"
elsif player_score == bank_score
message = "Push"
end
Что будет делать то, что вы хотите.
Если вы хотите оставить выражение case
с выражением , вам нужно убедиться, что when
-аргумент каждого when
-класса - это то, что отвечает на ===
таким образом, что имеет смысл для вашего сравнения.
Мы могли бы, для Например, используйте Range
с и Integer
с. Метод Range#===
проверяет, находится ли аргумент внутри Range
, а метод Integer#===
проверяет, является ли аргумент численно равным, поэтому мы можем переписать case
выражение, подобное этому:
case player_score
when 21
message = "Black Jack!"
when ((bank_score + 1)..)
message = "You win!"
when (22..)
message = "You lose!"
when ...bank_score
message = "You lose"
when bank_score
message = "Push"
end
Поскольку дела оцениваются сверху вниз, и вы можете оценить несколько условий в одном и том же случае, мы можем немного переставить их, чтобы сделать их приятнее для чтения:
case player_score
when 21
message = "Black Jack!"
when bank_score
message = "Push"
when 21.., ...bank_score
message = "You lose!"
when (bank_score..)
message = "You win!"
end
Также помните, что выражение case
является выражением , что означает, что оно оценивается как значение, а именно, по значению ветви, которая была оценена. Поэтому мы можем «вытянуть» присвоение message
:
message = case player_score
when 21
"Black Jack!"
when bank_score
"Push"
when 21.., ...bank_score
"You lose!"
when (bank_score..)
"You win!"
end
Обратите внимание, что это имеет немного семантику, отличную от той, что была у нас ранее: Раньше присвоение оценивалось только тогда, когда оценивалась одна из ветвей, в противном случае значение message
оставалось прежним , Принимая во внимание, что в этой форме присваивание всегда оценивается, и если ни одна из ветвей не оценивается, выражение case
оценивается как nil
.
Однако способ case
выражение записано, все случаи покрыты, поэтому всегда будет присваиваться не nil
значение.
Как только мы выполнили это преобразование, мы заметим, что в начале метода присваивается сообщение пустой строке ""
, а затем немедленно присваивается другое значение. Таким образом, мы можем избавиться от первого присваивания, так как его эффекты в любом случае немедленно перезаписываются.
И как только мы это сделаем, мы увидим, что мы присваиваем переменной message
и затем немедленно возвращаем ее. Таким образом, мы могли бы с таким же успехом вернуть значение выражения case
, например:
def end_game_message(player_score, bank_score)
case player_score
when 21
"Black Jack!"
when bank_score
"Push"
when 21.., ...bank_score
"You lose!"
when (bank_score..)
"You win!"
end
end