Я намагаюся створити неявний перетворювач, який би використовував неявний перетворювач, який зараз знаходиться в області застосування (eg. A => B)
і зможе конвертувати будь-який тип Traversable[A]
до Traversable[B]
.
Поки я отримав:
implicit def convertLists[A, B](from: Traversable[A])(implicit conv: A => B): Traversable[B] = from.map(conv)
Однак це не працює з:
val listOfB: List[B] = convertLists(List[A]())
Якщо я змінюся Traversable
до List
, тоді він працює добре, наприклад:
implicit def convertLists[A, B](from: List[A])(implicit conv: A => B): List[B] = from.map(conv)
Чи потрібно мені щось додати, щоб перетворювач міг прийняти будь-який підклас Traversable
?
Відповіді:
2 для відповіді № 1Ви чітко визначилися convertLists
повертати Traversable[B]
. Traversable
не підтип Росії List
(це його супертип), тому результат convertLists
(Traversable
) не може бути типом повернення listOfB
(List
)
Ви можете визначити convertLists
робити висновок типу результату на основі типу його аргументу, якщо ви використовуєте CanBuildFrom
:
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
// `CC` is some concrete subtype of `Traversable`
// `That` is an automatically inferred result collection type
implicit def convertLists[A, B, CC[T] <: TraversableLike[T, CC[T]], That](
from: CC[A]
)(
implicit
conv: A => B,
// witness that it"s possible to build
// a collection with elements `B` from a collection `CC[A]`,
// and compute the resulting collection type `That`
bf: CanBuildFrom[CC[A], B, That]
): That = from.map(conv)
Тепер припустимо наступне просте визначення A
і B
case class A(i: Int)
case class B(i: Int)
implicit def aisb(a: A): B = B(a.i)
Наступні роботи:
val listOfB: List[B] = convertLists(List[A](A(1)))
І вам не потрібно дзвонити convertLists
явно:
val listOfB2: List[B] = List[A](A(1))
2 для відповіді № 2
Використовуючи підхід у бібліотеці колекцій scala, ви можете вийти з таким кодом:
import scala.collection.generic.CanBuildFrom
import scala.collection.TraversableLike
implicit val boolToInt = (b: Boolean) => if (b) 1 else 0
implicit def convertLists[A, B, Repr, That](from: TraversableLike[A, Repr])(implicit conv: A => B, bf: CanBuildFrom[Repr, B, That]): That = from map conv
val listOfB: List[Int] = List(true, false)
що дає
listOfB: List[Int] = List(1, 0)