Les implicits de Scala peuvent-ils se composer pour convertir des types de kilomètres plus élevés?
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
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]) ...