В 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
не так элегантно, как вы надеялись, дайте нам больше контекста о вашей цели, и мы сможем найти элегантное решение, которое позволит избежать одновременного переключения.