Les implicits de Scala peuvent-ils se composer pour convertir des types de kilomètres plus élevés?

StackOverflow https://stackoverflow.com/questions/5485672

Question

Disons que j'ai un type appelé LongarRaywitable, qui est une représentation en boîte d'une gamme de longs. J'ai des définitions implicites qui convertissent entre ces types:

implicit def boxLongArray(array: Array[Long]) : LongArrayWritable { /*elided*/}
implicit def unboxLongArray(array: LongArrayWritable) : Array[Long] { /*elided*/}

Maintenant, j'ai également des implicits qui convertissent entre java.lang.iterable et scala.collection.list [x] dans leur forme générique:

implicit def iterator2list[X](it : java.lang.Iterable[X]) : List[X] { /* elided */ }
implicit def list2iterator[X](list : List[X]) : java.lang.Iterable[X] { /* elided */ }

Avec ces définitions, le compilateur Scala peut-il déduire une conversion implicite entre java.lang.iterable [longarraywitable] et list [array [long]] (l'équivalent de iterator2list(iterator).map(unboxLongArray(_))), ou est-ce au-delà des capacités des implicits, et nécessite donc sa propre définition implicite (explicite?)?

Merci,

Tim

Était-ce utile?

La solution

Il y a un article qui couvre cette question: Comment puis-je enchaîner les implicits à Scala? . Essentiellement, vous devez avoir une vue liée à la conversion en LongArrayWritable. Cela signifie, l'implicite def qui se convertit en LongArrayWritable reçoit un argument implicite (appelé View Bound) afin que l'argument à cela def n'est pas directement un Array mais un type qui peut être converti en un Array:

object LongArrayWritable {
  implicit def fromArraySource[A <% Array[Long]](a: A): LongArrayWritable = apply(a)
}
case class LongArrayWritable(a: Array[Long])

def test(a: LongArrayWritable): Unit = println("OK")

Maintenant, cela fonctionne pour les tableaux:

test(Array( 1L, 2L, 3L))

Cependant, depuis Array n'est pas un Iterable Et il n'y a pas de conversions par défaut de Iterable à Array Dans la portée, vous devez en ajouter un:

implicit def iterable2Array[A: ClassManifest](i: Iterable[A]): Array[A] = i.toArray

Ensuite, cela fonctionne:

test(List(1L, 2L, 3L))

la vue limitée A <% Array[Long] est un raccourci pour un argument implicite de type A => Array[Long], donc vous auriez également pu écrire

implicit def fromArraySource[A](a: A)(implicit view: A => Array[Long]) ...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top