В Ruby может ли метод coerce () знать, какой именно оператор требует помощи для принудительного вызова? - PullRequest
0 голосов
/ 11 мая 2010

В Ruby кажется, что с помощью

можно получить много справочной информации о coerce ().
def coerce(something)
  [self, something]
end

это когда

3 + rational
Требуется

, Fixnum 3 не знает, как обрабатывать добавление Rational, поэтому он просит Rational # coerce о помощи, вызываяational.coerce (3), и этот метод экземпляра coerce сообщит вызывающему: *

# I know how to handle rational + something, so I will return you the following:
[self, something]
# so that now you can invoke + on me, and I will deal with Fixnum to get an answer

Так что, если большинство операторов могут использовать этот метод, но не тогда, когда это (a - b)! = (B - a) ситуация? Может ли coerce () знать, какой это оператор, и просто обрабатывать эти особые случаи, просто используя простое [self, что-то] для обработки всех других случаев, когда (a op b) == (b op a)? (оп оператор).

Ответы [ 2 ]

1 голос
/ 11 мая 2010

Смысл coerce не в том, чтобы знать, какую операцию вы пытаетесь выполнить. Его цель - привести аргумент и self к общему пониманию. Кроме того, одни и те же операторы могут быть коммутативными в определенных классах, а не в других (например, Numeric#+ и Array#+), поэтому ваш маленький эксплойт на основе коммутативности coerce действительно не окупится.

Вместо того, чтобы заставлять ваш coerce делать то, для чего он не предназначен, вы должны вместо этого создать новый класс (например, ScalarPoint) и использовать его для сопряжения скалярных значений с вашим Point:

class ScalarPoint
  attr_reader :val

  def initialize(val)
    @val = val
  end

  def +(arg)
    case arg
    when Point:
      Point.new(@val + arg.x, @val + arg.y)
    when ScalarPoint:
      ScalarPoint.new(arg.val + @val)
    else
      raise "Unknown operand!"
    end
  end

  # define other operators, such as * etc

  def coerce(arg)
    return [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

и

class Point
  def coerce(arg)
    [ScalarPoint.new(arg), self] if arg.is_a?(Numeric)
    raise "Can't handle"
  end
end

и т.д.. (Примечание: код не проверен)

1 голос
/ 11 мая 2010

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

Это не так, как был разработан принудительный механизм Ruby. Как я ответил в на ваш предыдущий вопрос , coerce должен вернуть два эквивалентных значения [a, b], так что a.send(operator, b) будет работать независимо от оператора.

...