Ruby: два условия в заявлении Case - PullRequest
0 голосов
/ 10 ноября 2019

Как использовать оператор case и проверить наличие двух условий?

Мне нужно проверить, что элемент является массивом и содержит только строковые классы.

a = ['one','twon']  # => ["one", "twon"]

case a                                                                         # => 
when String
  puts "string
when Array && a.all?{|obj| obj.is_a?(String) }
   puts 'an array with only string classes'
else
  raise ArgumentError, "unsupported object #{obj}:#{obj.class}"
end

Приведенный выше кодвозвращает случай else, когда он должен возвращать инструкцию «массив только с строковыми классами»

Ответы [ 2 ]

4 голосов
/ 10 ноября 2019

Условия в операторе case не являются логическими выражениями;это значения, которые сравниваются с целевым объектом с помощью оператора ===. Конечно, любой класс может переопределить этот оператор, но предопределенный возвращает true только для небольшого набора условий (например, is_a?, равно, содержится в, =~ ...). Наличие логического выражения в качестве условия when не вызывает совпадения, если это выражение истинно;оно вызывает совпадение, когда целевой объект === имеет значение выражения, а для большинства объектов obj === true само по себе не соответствует действительности.

Так что вы можете поменять case на if / else цепочка в этом случае:

if a.is_a? String
  puts 'string'
elsif a.is_a?(Array) && a.all? { |obj| obj.is_a? String }
  puts 'an array with only string classes'
else
  raise ArgumentError, "unsupported object #{a}:#{a.class}"
end

Или выполнить вложенную проверку внутри условия дела. Но тогда у вас будет два else состояния, одно для if (что означает, что оно соответствует регистру массива, но не всех строк), и одно для case (что означает, что это было что-то совсем другое). Поэтому вместо того, чтобы дублировать код обработки ошибок, подобный этому, я использовал логическую переменную, чтобы указать, когда ошибка должна быть raise d:

ok = false
case a
 when String
  puts 'string'
  ok = true
 when Array
  if a.all? { |obj| obj.is_a? String }
    puts 'an array with only string classes'
    ok = true
  end
end
if !ok 
  raise ArgumentError, "unsupported object #{a}:#{a.class}"
end
0 голосов
/ 11 ноября 2019

Использовать сопоставление с образцом!

a = ['one','twon']

case a
in String
  puts 'string'
in Array if a.all?(String)
  puts 'an array with only string classes'
else
  raise ArgumentError, "unsupported object #{a}:#{a.class}"
end

* ruby ​​2.7+** экспериментальная функция

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...