/ / Неявне перетворення вмісту, що проходить у Scala, - скала, неявна конверсія

Неявне перетворення переміщуваного вмісту в Scala - scala, неявне перетворення

Я намагаюся створити неявний перетворювач, який би використовував неявний перетворювач, який зараз знаходиться в області застосування (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)