J'ai une méthode générique qui peut accepter n'importe quel tuple de n'importe quelle taille, la seule contrainte est que le premier élément de ce tuple soit de type MyClass
.
Quelque chose comme ça:
trait MyTrait[T <: (MyClass, _*)] {
getMyClass(x: T): MyClass = x._1
}
J'ai essayé ça
trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {
getMyClass(x: T): MyClass = x._1
}
mais j'obtiens l'erreur unboud wildcard type
C'est un peu dangereux, mais vous pouvez utiliser le type de structure dans ce cas:
trait MyTrait {
def getMyClass(x: {def _1: MyClass}): MyClass = x._1
}
Si vous souhaitez effectuer cette opération sans réflexion standard ou d'exécution, Sans forme est votre meilleur choix. Vous pouvez utiliser la classe de type IsComposite
pour appliquer des contraintes de niveau type au premier élément d'un tuple:
import shapeless.ops.Tuple.IsComposite
trait MustBeFirst
class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) {
def getMustBeFirst(x: P): MustBeFirst = ev.head(p)
}
Et alors:
scala> val good2 = (new MustBeFirst {}, "")
good2: (MustBeFirst, String) = ($anon$1@7294acee,"")
scala> val good3 = (new MustBeFirst {}, "", 123)
good3: (MustBeFirst, String, Int) = ($anon$1@6eff9288,"",123)
scala> val good4 = (new MustBeFirst {}, "", 'xyz, 123)
good4: (MustBeFirst, String, Symbol, Int) = ($anon$1@108cdf99,"",'xyz,123)
scala> val bad2 = ("abc", 123)
bad2: (String, Int) = (abc,123)
scala> new MyClass(good2)
res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76
scala> new MyClass(good3)
res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844
scala> new MyClass(good4)
res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478
scala> new MyClass(bad2)
<console>:15: error: could not find implicit value for parameter ev: shapeless.ops.Tuple.IsComposite[(String, Int)]{type H = MustBeFirst}
new MyClass(bad2)
^
Si vous devez utiliser un trait, vous pouvez insérer l'exigence ev
(pour "preuve") dans la définition plutôt que dans le constructeur:
trait MyTrait[P <: Product] {
implicit def ev: IsComposite[P] { type H = MustBeFirst }
}
Maintenant, toute classe instanciant MyTrait
devra fournir la preuve que P
est un tuple avec MustBeFirst
comme premier élément.
Scala ne peut pas utiliser un tuple générique de taille inconnue car les produits n'héritent pas eux-mêmes. Vous pouvez essayer d’utiliser Shapeless ou Products de play json lib.
Vous devez hériter de votre trait de Product
, grâce auquel vous pouvez avoir productIterator
, productArity
et, productElement
pour gérer la valeur renvoyée. Voici un exemple
case class MyClass()
trait MyTrait[T <: Product] {
def getMyClass(x: T): Option[MyClass] =
if(
x.productIterator.hasNext
&&
x.productIterator.next().isInstanceOf[MyClass]
){
Some(x.productIterator.next().asInstanceOf[MyClass])
} else {
None
}
}
case class Test() extends MyTrait[Product]
Et vous pouvez invoquer comme ça
Test().getMyClass((MyClass(), 1,3,4,5))
//res1: Option[MyClass] = Some(MyClass())
Test().getMyClass((1,3,4,5))
//res2: Option[MyClass] = None
J'espère que cela vous aide.