В моем проекте мне нужно написать универсальный класс, который в одном методе особым образом обрабатывает некоторые типы своим обработчиком (в примере для наглядности используется Numeric).
class A[T](val a:T){
def doSomething(b:T):T = a match{
case a : Int => doSomethingWithIntOrDouble(b)
case a : Double => doSomethingWithIntOrDouble(b)
case _ => b
}
def doSomethingWithIntOrDouble(b:T)(implicit ev:Numeric[T]):T =
ev.plus(a,b)
}
<console>:13: error: could not find implicit value for parameter ev: Numeric[T]
case a : Int => doSomethingWithIntOrDouble(b)
^
<console>:14: error: could not find implicit value for parameter ev: Numeric[T]
case a : Double => doSomethingWithIntOrDouble(b)
Я думаю, это происходит потому, что компилятор выбирает параметр типа, а не фактический. Скажите, есть ли способ обойти это?
PS Ладно. Если предположить, что ответ правильный, то для достижения полиморфизма необходимо перегрузить метод dosomething.
class A[T](val a:T){
def doSomething(b:T)(implicit ev:Numeric[T]):T = ev.plus(a,b)
def doSomething(b:T):T = b
}
Но в этом случае возникает другая проблема.
scala> a.doSomething(2)
<console>:13: error: ambiguous reference to overloaded definition,
both method doSomething in class A of type (b: Int)Int
and method doSomething in class A of type (b: Int)(implicit ev: Numeric[Int])Int
match argument types (Int)
a.doSomething(2)





Я не совсем уверен, что это нужно вам, но я надеюсь, что это поможет.
По сути, вам нужно передать внешнему методу свидетельство того, что тип T является Числовой. Но вы также должны обрабатывать случай, когда это не так.
В этом случае вы можете указать значение по умолчанию для неявного параметра следующим образом:
class A[T](val a: T) {
def doSomething(b: T)(implicit ev: Numeric[T] = null): T = Option(ev) match {
case Some(ev) => doSomethingWithNumeric(b)(ev)
case None => b
}
def doSomethingWithNumeric(b: T)(implicit ev: Numeric[T]): T =
ev.plus(a, b)
}
Кажется, это работает.
(new A(10)).doSomething(100) // res: Int = 110
(new A("hey")).doSomething("world") // res: String = "world"
Обратите внимание, что если у вас будет много методов, возможно, самым чистым решением будет создание Aчерта с двумя реализациями, одна для числовых типов, а другая — без числовых типов.
Сделайте конструкторы обоих подклассов закрытыми и создайте фабрика для A в сопутствующем объекте, который запрашивает неявный числовой параметр, и, если он будет найден, он вернет новый экземпляр числового подкласса.