Próbuję utworzyć niejawny konwerter, który użyłby niejawnego konwertera, który jest obecnie objęty zakresem (eg. A => B)
i byłby w stanie przekonwertować dowolny typ Traversable[A]
do Traversable[B]
.
Do tej pory mam:
implicit def convertLists[A, B](from: Traversable[A])(implicit conv: A => B): Traversable[B] = from.map(conv)
Nie działa to jednak z:
val listOfB: List[B] = convertLists(List[A]())
Jeśli się zmienię Traversable
do List
, to działa dobrze, np .:
implicit def convertLists[A, B](from: List[A])(implicit conv: A => B): List[B] = from.map(conv)
Czy muszę dodać coś jeszcze, aby konwerter mógł zaakceptować dowolną podklasę Traversable
?
Odpowiedzi:
2 dla odpowiedzi № 1Wyraźnie zdefiniowałeś convertLists
wracać Traversable[B]
. Traversable
nie jest podtypem List
(to jego nadtyp), więc wynik convertLists
(Traversable
) nie może być typem zwracanym listOfB
(List
).
Możesz zdefiniować convertLists
aby wywnioskować typ wyniku na podstawie typu jego argumentu, jeśli używasz 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)
Teraz przyjmując następującą prostą definicję A
i B
case class A(i: Int)
case class B(i: Int)
implicit def aisb(a: A): B = B(a.i)
Następujące prace:
val listOfB: List[B] = convertLists(List[A](A(1)))
I nie musisz dzwonić convertLists
jawnie:
val listOfB2: List[B] = List[A](A(1))
2 dla odpowiedzi nr 2
Stosując podejście z biblioteki kolekcji scala, możesz wyjść z takim kodem:
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)
co daje
listOfB: List[Int] = List(1, 0)