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" # 28.29
Мы не настаиваем на таком решении. Но рекомендуем реализовывать coerce
при создании любого класса для работы с числовыми данными.
5.17. Поразрядные операции над числами
Иногда требуется работать с двоичным представлением объекта Fixnum
. На прикладном уровне такая необходимость возникает нечасто, но все-таки возникает.
Ruby обладает всеми средствами для таких операций. Для удобства числовые константы можно записывать в двоичном, восьмеричном или шестнадцатеричном виде. Поразрядным операциям И, ИЛИ, ИСКЛЮЧАЮЩЕЕ ИЛИ и НЕ соответствуют операторы &
, |
, ^
и ~
.
x = 0377 # Восьмеричное (десятичное 255)
y = 0b00100110 # Двоичное (десятичное 38)
z = 0xBEEF # Шестнадцатеричное (десятичное 48879)
а = x | z # 48895 (поразрядное ИЛИ)
b = x & z # 239 (поразрядное И)
с = x ^ z # 48656 (поразрядное ИСКЛЮЧАЮЩЕЕ ИЛИ)
d = ~ y # -39 (отрицание или дополнение до 1)
Метод экземпляра size
позволяет узнать размер слова для той машины, на которой исполняется программа.
size # Для конкретной машины возвращает 4.
Имеются операторы сдвига влево и вправо ( <<
и >>
соответственно). Это логические операторы сдвига, они не затрагивают знаковый бит (хотя оператор >>
распространяет его).
x = 8
y = -8
а = x >> 2 # 2
b = y >> 2 # -2
с = x << 2 # 32
d = y << 2 # -32
Конечно, если сдвиг настолько велик, что дает нулевое значение, то знаковый бит теряется, поскольку -0 и 0 — одно и то же.
Квадратные скобки позволяют трактовать числа как битовые массивы. Бит с номером 0 всегда является младшим, вне зависимости от порядка битов в конкретной машинной архитектуре.
x = 5 # То же, что 0b0101
а = x[0] # 1
b = x[1] # 0
с = x[2] # 1
d = x[3] # 0
# И так далее # 0
Присваивать новые значения отдельным битам с помощью такой нотации невозможно (поскольку Fixnum
хранится как непосредственное значение, а не как ссылка на объект). Но можно имитировать это действие путем сдвига 1 влево на нужное число позиций с последующим выполнением операции ИЛИ или И.
# Выполнить присваивание x[3] = 1 нельзя,
# но можно поступить так:
x |= (1<<3)
# Выполнить присваивание x[4] = 0 нельзя,
# но можно поступить так:
x &= ~(1<<4)
5.18. Преобразование системы счисления
Ясно, что любое целое число можно представить в любой системе счисления, поскольку хранятся эти числа в двоичном виде. Мы знаем, что Ruby умеет работать c целыми константами, записанными в любой из четырех наиболее популярных систем. Следовательно, разговор о преобразовании системы счисления может вестись только применительно к числам, записанным в виде строк.
Вопрос о преобразовании строки в целое рассмотрен в разделе 2.24. Для преобразования числа в строку проще всего воспользоваться методом to_s
, которому можно еще передать основание системы счисления. По умолчанию оно равно 10, но в принципе может быть любым вплоть до 36 (когда задействованы все буквы латинского алфавита).
237.to_s(2) # "11101101"
Читать дальше
Конец ознакомительного отрывка
Купить книгу