Ruby: Как мне вызвать функцию через ссылку на объект?
Рассмотрим этот надуманный пример:
# Dispatch on value of fruit_kind:
TYPE_A = :apple
TYPE_B = :banana
TYPE_C = :cherry
eating_method = nil
case fruit_kind
# Methods to use for different kinds of fruit (assume these are
# already defined)
when TYPE_A then eating_method = bite
when TYPE_B then eating_method = peel
when TYPE_C then eating_method = om_nom_nom
end
Теперь я хотел бы вызвать цель eating_method
с некоторыми аргументами:
# Doesn't work; this tries to invoke a method called "eating_method",
# not the reference I defined earlier.
eating_method(some_fruit)
Какой правильный способ сделать это в Ruby?
4 ответа
Использование send
, Send принимает имя функции, поэтому используйте символы:
case fruit_kind
# Methods to use for different kinds of fruit (assume these are
# already defined)
when TYPE_A then eating_method = :bite
when TYPE_B then eating_method = :peel
when TYPE_C then eating_method = :om_nom_nom
end
send(eating_method, some_fruit)
РЕДАКТИРОВАТЬ:
Кстати, вы знали, что можете сделать это case
немного красивее, делая что-то вроде этого:
eating_method = case fruit_kind
# Methods to use for different kinds of fruit (assume these are
# already defined)
when TYPE_A then :bite
when TYPE_B then :peel
when TYPE_C then :om_nom_nom
else nil
end
Или, как упоминает Sii, вместо этого используйте хеш:
fruit_methods = {:apple => :bite, :banana => :peel, :cherry => :om_nom_nom}
send(fruit_methods[fruit_kind], some_fruit)
В Ruby вы можете использовать классы и методы, как если бы они были значениями без особой работы, поэтому вы можете сократить объем, которым вы фактически должны управлять в своем примере, до единого определения Class -> Method и использовать обобщенный алгоритм для работы с этим. определение.
Предположим, что каждый из ваших типов реализует указанные вами методы, например, определены Apple.bite(), Banana.peel() и Cherry.om_nom_nom(). Также предположим, что fruit является экземпляром fruit_kind. Вы можете управлять отображением в одном месте и использовать обобщенный метод для выполнения всей оценки метода, специфичной для класса, например:
fruit_table = {Apple => :bite,
Banana => :peel,
Cherry => :om_nom_nom}
eating_method = fruit.method(fruit_table[fruit.type])
eating_method.call
Обратите внимание, что ссылка eat_method является экземпляром объекта метода, специфичным для экземпляра fruit. Вы можете извлечь определение таблицы как переменную класса, но вы захотите оценивать fruit.method в контексте каждого момента, когда вы решаете, какую функцию вызывать в передаваемом вами экземпляре.
Формулировка меня сильно смущает.
Вы, вероятно, хотите Object# отправить, хотя.
Объектная модель Ruby позволяет вам динамически вызывать методы, используя Object#send
метод, который принимает символ как метод, который вы хотите вызвать.
Поэтому, если бы у вас был класс FruitEater, вы могли бы отправить метод поедания следующим образом:
f = FruitEater.new
# Dispatch on value of fruit_kind:
TYPE_A = :apple
TYPE_B = :banana
TYPE_C = :cherry
eating_method = nil
case fruit_kind
# Methods to use for different kinds of fruit (assume these are
# already defined)
when TYPE_A then eating_method = :bite
when TYPE_B then eating_method = :peel
when TYPE_C then eating_method = :om_nom_nom
end
f.send(eating_method)