Из-за отсутствия лучшего примера предположим, что у меня есть тип контейнера, который принимает один тип параметра. Предположим, что этот контейнер обертывает список того же типа. Я хотел бы определить метод в моем новом контейнере таким образом, что всякий раз, когда выполняется операция, он делегирует вызов во встроенный список, но в результате он возвращает мой тип контейнера (возможно, другого параметра типа). Для этого я буду использовать шаблон неявного построителя из коллекций scala. Вот основная структура:Каковы правила приоритета при выборе неявного использования для функции CanBuildFrom
class Foo[A](val data: List[A]) {
def foo[C, That](pf: PartialFunction[A, C])(
implicit bf: CanBuildFrom[Foo[_], C, That]
): That = {
bf(new Foo(data.collect(pf))).result
}
}
object Foo {
def newBuilder[A]: Builder[A, Foo[A]] =
new ArrayBuffer[A] mapResult { r => new Foo(r.toList) }
implicit def canBuildFrom[A]: CanBuildFrom[Foo[_], A, Foo[A]] =
new CanBuildFrom[Foo[_], A, Foo[A]] {
def apply(from: Foo[_]) = newBuilder
def apply() = newBuilder
}
}
Так что это работает, как я ожидал бы возвращая когда мой пф переходит из Int в строку Foo [String]:
scala> val f = new Foo(List(1,2,3))
f: Foo[Int] = [email protected]
scala> f.foo { case x => x.toString }
res318: Foo[java.lang.String] = [email protected]
Хотя предыдущий пример был основан на имеющем CanBuildFrom, который принимает тип «от» Foo [_], тип элемента «A» и преобразуется в тип «to» типа «Foo [A]». То, что я хотел бы сделать, это взять «из» типа List [_], тип элемента «A» и преобразовать в «to» тип «Foo [A]». Что-то вдоль этих линий:
class Foo[A](val data: List[A]) {
def foo[C, That](pf: PartialFunction[A, C])(
implicit bf: CanBuildFrom[List[_], C, That]
): That = {
data.collect(pf)(bf)
}
}
object Foo {
def newBuilder[A]: Builder[A, Foo[A]] =
new ArrayBuffer[A] mapResult { r => new Foo(r.toList) }
implicit def canBuildFrom[A]: CanBuildFrom[List[_], A, Foo[A]] =
new CanBuildFrom[List[_], A, Foo[A]] {
def apply(from: List[_]) = newBuilder
def apply() = newBuilder
}
}
Здесь я прошел мой неявный параметр CanBuildFrom прочь к классу List непосредственно, так что он может построить свой Foo класс для хранения результатов в Тем не менее, когда я запускаю тот же самый тест, вместо этого. получения Foo [String], я получаю List [String]. Другими словами, он не использует мой неявный, он использует общую версию.
scala> val f = new Foo(List(1,2,3))
f: Foo[Int] = [email protected]
scala> f.foo { case x => x.toString }
res319: List[java.lang.String] = List(1, 2, 3)
Итак, мой вопрос: почему? Я бы подумал, что если мой текущий тип - Foo, и я конвертирую в Foo, и есть неявный fn в области, соответствующий входным параметрам (List в этом случае), тогда это будет наилучшее совпадение. Я делаю что-то неправильно или это по соображениям безопасности, что коллекция «из» имеет наибольшее преимущество в выборе того, для какой коллекции она конвертируется. Есть ли что-то, что я могу сделать, чтобы повысить приоритет моего неявного?
Спасибо за комментарии , Да, я проверил неявный, который был на самом деле в области ранее до публикации. Дело в том, что я не хочу указывать тип, я хочу, чтобы тип дела выполнял работу. Я думал, что мой неявный должен иметь приоритет, но я думаю, что это будет не так, пока он не вступит в метод foo. Единственное решение, о котором я могу думать, это заменить «Это» на «Foo [C]», поэтому тип «to» явно. Это работает, но проблема в том, что если у меня нет поддержки типа «C» с «Foo», я бы хотел, чтобы он использовал более общий тип (в соответствии с шаблоном CanBuildFrom). Это не сработает. – Mike