Il semble que Premier et Deuxième sont identiques, mais pourquoi?
Premier
trait PartialFunction[-A, +B] extends (A => B)
Deuxième
val iter2 = List(1, 2, 3, 4, 5).iterator
val second = iter2.collect {
case i:Int if i > 0 && i < 3 => i
}
second.foreach((println(_)))
Est-ce parce que le compilateur Scala convertit automatiquement
{case i: Int if i> 0 && i i} dans la forme d'implémentation de First avec génération de isDefinedAt à partir de if i> 0 && i part?
Aussi, case i: Int if i> 0 && i i est un modèle de classe Case correspondant, si je suis correct. Cependant, dans scala / src / library /scala/PartialFunction.scala , il n'y a pas de définition de classe Case pour PartialFunction.
val iter = List(1, 2, 3, 4, 5).iterator
val first = iter.collect(new PartialFunction[Int, Int]{
def apply(i: Int) = i
def isDefinedAt(i: Int) = i > 0 && i < 3
})
first.foreach((println(_)))
Alors pourquoi cette correspondance de modèle de classe case fonctionne ?
Je suppose que le compilateur Scala fait beaucoup de travaux implicites intelligemment mais cela me déroute de comprendre ce qui se passe et comment écrire du code Scala.
S'il y a de bonnes références, au lieu du langage ou spécifications du compilateur, pour comprendre Syntaxe du code Scala et manière d'écrire du code Scala, veuillez suggérer.
3 Réponses :
Oui, le compilateur convertit la deuxième version en une PartialFunction [Int, Int] (car c'est ce que prend collect ).
Il n'y a pas de correspondance de classe de cas ici, et elle ne correspond même pas sur le type car la valeur doit être Int (et donc la déclaration de type dans la deuxième version est pas obligatoire).
Le guide de style donne de nombreux conseils sur la manière dont Scala est généralement écrite. p>
Est-ce parce que le compilateur Scala convertit automatiquement {case i: Int if i> 0 && i i} en la forme d'implémentation de First en générant isDefinedAt à partir de ** if i> 0 && i
Oui, la traduction exacte est donnée dans Fonctions anonymes de correspondance de modèle . Ici, ce sera
new PartialFunction[Int, Int]{ def apply(x: Int) = x match { case i:Int if i > 0 && i < 3 => i } def isDefinedAt(x: Int) = x match { case i:Int if i > 0 && i < 3 => true case _ => false } }Notez la différence avec votre premier exemple dans
apply! Vous pouvez toujours l'appeler lorsqueisDefinedest false.De plus, case i: Int si i> 0 && i i est une correspondance de modèle de classe Case, si j'ai raison
Si quoi que ce soit, c'est l'inverse; Les classes de cas sont appelées de cette façon car elles peuvent être mises en correspondance avec des modèles et la correspondance de modèles utilise le mot clé
casedans Scala.
La spécification n'est pas à jour là-bas, alors j'ai posté la traduction exacte. Je vais créer un ticket, car il reste encore beaucoup de temps pour mettre à jour la spécification de Scala 3, qui n'a pas encore de spécification. Je vais également créer un ticket pour une spécification à la fois à jour et que vous pouvez lire pour le plaisir et le profit.
Pour votre exemple
def apply(x: T1): R = applyOrElse(x, PartialFunction.empty)
La fonction partielle générée par le compilateur définit applyOrElse car elle est plus efficace que l'idiome naïf:
if (pf.isDefinedAt (x)) pf.apply (x) else ???
Montrant cette implémentation, qui est similaire à ce qui est décrit dans la spécification: p >
$ scalac -Vprint:typer pf.scala
[[syntax trees at end of typer]] // pf.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>(): Main.type = {
Main.super.<init>();
()
};
def f: IndexedSeq[Int] = scala.Predef.intWrapper(1).to(5).collect[Int](({
@SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Int,Int] with java.io.Serializable {
def <init>(): <$anon: Int => Int> = {
$anonfun.super.<init>();
()
};
final override def applyOrElse[A1 <: Int, B1 >: Int](x1: A1, default: A1 => B1): B1 = ((x1.asInstanceOf[Int]: Int): Int @unchecked) match {
case (i @ _) if i.>(0).&&(i.<(3)) => i
case (defaultCase$ @ _) => default.apply(x1)
};
final def isDefinedAt(x1: Int): Boolean = ((x1.asInstanceOf[Int]: Int): Int @unchecked) match {
case (i @ _) if i.>(0).&&(i.<(3)) => true
case (defaultCase$ @ _) => false
}
};
new $anonfun()
}: PartialFunction[Int,Int]))
}
}
où AbstractPartialFunction définit
object Main {
def f = (1 to 5).collect { case i if i > 0 && i < 3 => i }
}
Voici un lien externe vers une modification pour utiliser applyOrElse . La PartialFunction améliorée remonte à 2012. La fonctionnalité est probablement sous-documentée ou sous- annoncé. Certaines informations sont disponibles en développant le Scaladoc pour PartialFunction . Pour une raison quelconque, ce lien affiche orElse , vous devrez donc faire défiler vers l'arrière pour applyOrElse . Il semble que la documentation soit difficile.
Non, la correspondance de modèles ne fonctionne pas uniquement sur les classes de cas.