Приложение Ruby, использующее When/Case, дает Nil, когда не должно

Следующий код должен напечатать один из трех вариантов, заданных в зависимости от результатов любой из проверок ==, но это не так. Это дает nil для любого значения your_message, предоставленного через 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

Итак, вы хотите проверить, равно ли содержимое your_message значению true или false? Я думаю, вам нужно вернуться и перечитать документацию по .include? и на случае.

pjs 30.03.2023 02:49

Привет pjs ... спасибо за ваш отзыв. Помимо чтения документации, я хотел бы пообщаться со своими старшими/коллегами, чтобы понять ошибку или ошибку... Я знаю, как включать и обрабатывать кейсы, чего я не знаю, так это почему в моем текущем контексте код не работает. работает по назначению. Есть идеи?. Спасибо.

Panamaniac507 30.03.2023 02:55

«Я умею включать и работать с кейсами». Извините, но это явно не так. Отсюда мое предложение просмотреть документацию.

pjs 30.03.2023 02:57

Большой совет: если вы знаете, что .include? возвращает либо true, либо false, запустите свой выбор irb или pry и посмотрите, что произойдет, когда вы введете "some string" == true или "some string" == false. Тогда попробуйте это, используя ===. Вы должны понять, почему ваше утверждение case никогда не дает совпадений.

pjs 30.03.2023 03:08

Явные возвраты в вашем редактировании не нужны. Отдельно стоит отметить, что считается плохим этикетом SO коренным образом изменить ваш вопрос таким образом, чтобы сделать недействительными существующие ответы. Обычно правильнее всего открыть связанный вопрос, который ссылается на оригинал, если у вас есть отдельные дополнительные вопросы.

Todd A. Jacobs 30.03.2023 07:13

Если этот комментарий недостаточно проясняет ваши последующие изменения - я думаю, что да, но ваш пробег может отличаться - тогда, пожалуйста, откройте новый вопрос о том, как выполнить дополнительное сравнение, которое вы хотите, в выражении случая, и, возможно, получить лучшее объяснение, чем может уместиться в комментариях, о том, почему это сравнение не делает того, что вы ожидаете.

Todd A. Jacobs 30.03.2023 07:29

Привет, Тодд, большое спасибо за ваш ценный комментарий... Мне удалось заставить его работать. Ваше утверждение абсолютно верно... проблема заключалась в порядке моих проверок... это было ключевым моментом. И, конечно же, тот факт, что ранее я сравнивал строку с логическим значением... большое спасибо за вашу решительную и терпеливую поддержку.

Panamaniac507 30.03.2023 09:16
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
1
7
124
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В выражении casewhen сравнивает значение со значением.

В вашем случае вы сравниваете 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

Спасибо, ребята... Я усовершенствовал свой код следующим образом, но при использовании следующих тестовых строк TEST! и тест не дает правильных результатов в соответствии с моим кодом...

Panamaniac507 30.03.2023 05:52
Ответ принят как подходящий

Падежные выражения и триквалы

Падежное выражение работает не так, как вы думаете. Это не просто еще один способ выразить условия if/then. Под капотом case реализует оператор === для выражения при передаче аргумента case или позволяет вам использовать его как набор операторов if, если вы не передаете начальный аргумент. Он также выполняет сопоставление с образцом, но это выходит за рамки этого вопроса.

Отбрасывание аргумента в управляющее выражение

Когда вы предоставляете аргумент case, такой как case your_message, тогда каждый оператор when будет оцениваться как выражение против аргумента с использованием тройки, специфичной для класса, а не условного выражения, которое, как вы думаете, вы ему даете. Это легко исправить, передав аргумент в case. Например:

your_message = "foo?"

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

#=> "bar"

Теперь, вместо того, чтобы эффективно произносить "foo?" === true (что, очевидно, вернет false), Ruby просто оценивает, является ли когда-утверждение правдивым или нет. Основываясь на вашем существующем коде, это, вероятно, самый простой способ получить ожидаемое поведение.

Использование Proc, Lambda или Regexp с Threequals

В качестве альтернативы вы можете реструктурировать свой оператор case, чтобы использовать процедуры, лямбда-выражения или даже регулярные выражения, которые могут соответствовать тройному сравнению, поскольку оно реализовано классом. Например, рассмотрим следующий пример, в котором используется Proc#=== для сравнения результатов лямбда.

your_message = "foo? \n"

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

#=> "baz"

Это в основном передает аргумент case (например, your_message) в лямбду, где вы затем можете вызывать методы для аргумента, чтобы оценить его истинность. Это более сложный подход, но он может быть полезен.

Поскольку регулярные выражения также поддерживают метод threequals, вы можете использовать и его:

your_message = "foo?"

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

#=> "quux"

Другие проблемы с вашим кодом

Вы также должны учитывать такие вещи, как зависимость от порядка. В вашем примере кода, даже если бы не было других проблем, "I am going to work now!" никогда не будет сопоставляться, потому что предыдущие операторы when (если они работают) будут возвращать значение, основанное на наличии или отсутствии знака вопроса, прежде чем вы когда-либо достигли этого конкретного сравнения . Выражения case не «проваливаются», как в других языках, поэтому вам необходимо учитывать приоритет операторов так же, как и в управляющем выражении if/elsif/else/end.

Рабочий пример

Следующее намного проще и отлично работает. Он возвращает действительные результаты и не возвращает ноль. Предполагается, что 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 правильный и вы используете правильный тип выражения для сравнений, вы можете заставить выражение case делать то, что хотите, но не обязательно так, как вы изначально ожидали.

Привет, Тодд... твои комментарии ОЧЕНЬ полезны, большое спасибо. Я переупорядочил свои случаи КОГДА... однако мой "когда your_message.upcase && your_message.include?("!")" не работает должным образом... в основном, он возвращает выражение, когда тестовая строка " тест!" что неверно... оно должно возвращать выражение ТОЛЬКО при выполнении ОБА условий... это "ТЕСТ!". Любые мысли? Большое спасибо,

Panamaniac507 30.03.2023 06:23

@ Panamaniac507 Вам нужно будет открыть отдельный вопрос об этом, если вы хотите получить подробный ответ. Короткая версия заключается в том, что ваше первое выражение не возвращает логическое значение. Вы, вероятно, хотите when your_message.eql?(your_message.upcase) && your_message.end_with?("!"), но трудно сказать, не видя полного контекста. Почти все в Ruby является выражением, поэтому важно понимать истинность, приоритет и сравнение выражений. Возможно, вы захотите придерживаться для этого операторов if, поскольку они больше соответствуют тому, как вы думаете о своем коде.

Todd A. Jacobs 30.03.2023 07:06

Другие вопросы по теме