В Ruby, как включить переменную, содержащую объект класса?

Если я напишу это:

case v
when String
  puts :String
else
  puts :other
end

Если я установлю v в "some string" Я получаю "String".

Если я установлю v в StringЯ получаю "другое".

Как я должен "переключаться" на переменную, содержащую один из нескольких объектов класса?

Как это соблюдает устоявшийся вычислительный принцип "наименьшего удивления"?

Пожалуйста, не говорите мне, чтобы я исправлял класс "Class".

4 ответа

Я согласна с тем что ===(тест, используемыйcaseможет сбивать с толку.

Это часто называют "оператором равенства случая", но===не является ни рефлексивным, ни симметричным, ни транзитивным, поэтому он не ведет себя как равенство вообще:

String === "test"
# true
"test" === String
# false
String === String
# false
String === Class
# false
Class === String
# true
Class === Class
# true

Лучшее описание, которое я прочитал дляa === bэто ответ@JörgWMittag:

" Если у меня есть ящик с надписью aимеет ли смысл ставитьb в этом ящике?"

Для вашей проблемы вы можете написать:

v = String
case v
when Class
  puts "#{v} is a Class, let's investigate some more"
  # another case, if statements or hash lookup...
else
  puts :other
end

Ты можешь использовать case без объекта:

case 
when v == String
  puts 'v is String class'
when v.is_a?(String)
  puts 'v is an instance of String'
else
  puts 'v is something else'
end

Это напоминает if-elsif-else выражение.

Как я должен "переключаться" на переменную, содержащую один из нескольких объектов класса?

С Module#<=:

case v
when String then "instance of string"
when ->(c) { c <= String } then "class derived from String"
end

Как это соблюдает устоявшийся вычислительный принцип "наименьшего удивления"?

В совершенстве.

Выражения падежа в ruby ​​и некоторых других функциональных языках весьма отличаются от их двоюродных братьев в выражениях с обязательным переключением.

Как уже упоминалось, в выражениях используются === метод, который является методом определения шаблона. в a === b парадигма, a это шаблон, который описывает коллекцию возможных экземпляров. b это экземпляр, который потенциально вписывается в этот шаблон / коллекцию. Думать о a === b как:

"а" описывает "б"?

или же

"а" содержит "б"?

Как только вы поймете это, String === String #=> false это не так удивительно, потому что String это пример Class так что вписывается в Class шаблон.


Другое уникальное различие между падежными выражениями и операторами switch заключается в том, что падежные выражения - это просто выражения. Что означает, что вы можете делать классные вещи, как это:

puts case v.name
  when "String"
    :String
  else
    :other
  end if v.is_a? Class

Этот код выполняется только если v это класс, потом включается v.name а также puts все, что вы хотите, основываясь на названии класса.

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

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