строгий метод to_str. Из всех встроенных классов только String и Exception реализуют to_str, и лишь String, Regexp и Marshal вызывают его. Увидев сообщение TypeError: Failed to convert xyz into string, можно смело сказать, что интерпретатор пытался вызвать to_str и потерпел неудачу.

Вы можете реализовать метод to_str и самостоятельно, например, если хотите, чтобы строку можно было конкатенировать с числом:

class Numeric

 def to_str

  to_s

 end

end

label = 'Число ' + 9 # 'Число 9'

Аналогично обстоит дело и в отношении массивов. Для преобразования объекта в массив служит метод to_a, а метод to_ary вызывается, когда ожидается массив и ничего другого, например в случае множественного присваивания. Допустим, есть предложение такого вида:

а, b, с = x

Если x — массив из трех элементов, оно будет работать ожидаемым образом. Но если это не массив, интерпретатор попытается вызвать метод to_ary для преобразования в массив. В принципе это может быть даже синглетный метод (принадлежащий конкретному объекту). На само преобразование не налагается никаких ограничений, ниже приведен пример (нереалистичный), когда строка преобразуется в массив строк:

class String

 def to_ary

  return self.split('')

 end

end

str = 'UFO'

a, b, с = str # ['U', 'F', 'O']

Метод inspect реализует другое соглашение. Отладчики, утилиты типа irb и метод отладочной печати p вызывают inspect, чтобы преобразовать объект к виду, пригодному для вывода на печать. Если вы хотите, чтобы во время отладки объект раскрывал свое внутреннее устройство, переопределите inspect.

Есть и еще одна ситуация, когда желательно выполнять такие преобразования «за кулисами». Пользователь языка ожидает, что Fixnum можно прибавить к Float, а комплексное число Complex разделить на рациональное. Но для проектировщика языка это проблема. Если метод + класса Fixnum получает аргумент типа Float, то что он должен с ним делать? Он знает лишь, как складывать значения типа Fixnum. Для решения проблемы в Ruby реализован механизм приведения типов coerce.

Когда оператор + (к примеру) получает аргумент, которого не понимает, он пытается привести вызывающий объект и аргумент к совместимым типам, а затем значения этих типов сложить. Общий принцип использования метода coerce прямолинеен:

class MyNumberSystem

 def +(other)

  if other.kind_of?(MyNumberSystem)

   result = some_calculation_between_self_and_other

   MyNumberSystem.new(result)

  else

   n1, n2 = other.coerce(self)

   n1 + n2

  end

 end

end

Метод coerce возвращает массив из двух элементов: аргумент и вызывающий объект, приведенные к совместимым типам.

В примере выше мы полагались на то, что класс аргумента умеет как-то выполнять приведение. Будь мы законопослушными гражданами, реализовали бы приведение и в собственном классе, чтобы он мог работать с числами других видов. Для этого нужно знать, с какими типами мы можем работать напрямую, и приводить объект к одному из этих типов, когда возникает необходимость. Если мы сами не знаем, как это сделать, следует спросить у родителя:

def coerce(other)

 if other.kind_of?(Float)

  return other, self.to_f

 elsif other.kind_of?(Integer)

  return other, self.to_i

 else

  super

 end

end

Конечно, чтобы этот пример работал, наш объект должен реализовывать методы to_i и to_f.

Метод coerce можно использовать для реализации автоматического преобразования строк в числа, как это делается в языке Perl:

class String

 def coerce(n)

  if self['.']

   [n, Float(self)]

  else

   [n, Integer(self)]

  end

 end

end

x = 1 + '23' # 24

y = 23 * '1.23' # 29.29

Впрочем, поступать так необязательно. Однако мы настоятельно рекомендуем реализовывать метод coerce при разработке разного рода числовых классов.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату