Да и нет. Да, вы можете сделать так, чтобы выглядело , как будто вы добавили метод к double
. Например:
class MyRichDouble(d: Double) {
def <>(other: Double) = d != other
}
implicit def doubleToSyntax(d: Double) = new MyRichDouble(d)
Этот код добавляет ранее недоступный оператор <>
к любому объекту типа Double
. Пока метод doubleToSyntax
находится в области видимости, чтобы его можно было вызывать без квалификации, будет работать следующее:
3.1415 <> 2.68 // => true
Часть ответа «нет» проистекает из того факта, что вы на самом деле ничего не добавляете в класс Double
. Вместо этого вы создаете преобразование из Double
в новый тип, который определяет нужный метод. Это может быть гораздо более мощная техника, чем открытые классы, предлагаемые многими динамическими языками. Это также оказывается полностью безопасным для типов. : -)
Некоторые ограничения, о которых вам следует знать:
- Этот метод не позволяет вам удалить или переопределить существующих методов, просто добавьте новые
- Неявный метод преобразования (в данном случае
doubleToSyntax
) обязательно должен находиться в области видимости, чтобы требуемый метод расширения был доступен
Идиоматически, неявные преобразования либо помещаются в одноэлементные объекты и импортируются (например, import Predef._
), либо в черты и наследуются (например, class MyStuff extends PredefTrait
).
Небольшое отступление: «операторы инфикса» в Scala на самом деле являются методами. Нет никакой магии, связанной с методом <>
, который позволяет ему быть инфиксным, парсер просто принимает его таким образом. Вы также можете использовать «обычные методы» в качестве инфиксных операторов, если хотите. Например, класс Stream
определяет метод take
, который принимает один параметр Int
и возвращает новый Stream
. Это можно использовать следующим образом:
val str: Stream[Int] = ...
val subStream = str take 5
Выражение str take 5
буквально идентично str.take(5)
.