/ / Implikowana konwersja zawartości dostępnej w Scali - scala, niejawna konwersja

Niejawna konwersja Treści wychodzących w Scala - scala, implicit-conversion

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 № 1

Wyraź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)