web-dev-qa-db-fra.com

Les "opérations postfixes" de Scala

J'ai cherché pendant une demi-heure et je n'arrive toujours pas à le comprendre.

Dans SIP: Modularizing Language Features il existe un certain nombre de fonctionnalités qui nécessiteront une "activation" explicite dans Scala 2.10 (import language.feature). Parmi eux, il y a postfixOps, auquel je ne trouve aucune référence nulle part. Que permet exactement cette fonctionnalité?

55
dmitry

Il vous permet d'utiliser la syntaxe de l'opérateur en position postfixée. Par exemple

List(1,2,3) tail

plutôt que

List(1,2,3).tail

Dans cet exemple inoffensif, ce n'est pas un problème, mais cela peut conduire à des ambiguïtés. Cela ne compilera pas:

val appender:List[Int] => List[Int] = List(1,2,3) ::: //add ; here
List(3,4,5).foreach {println}

Et le message d'erreur n'est pas très utile:

    value ::: is not a member of Unit

Il essaie d'appeler le ::: méthode sur le résultat de l'appel foreach, qui est de type Unit. Ce n'est probablement pas ce que le programmeur voulait. Pour obtenir le résultat correct, vous devez insérer un point-virgule après la première ligne.

58
Kim Stebel

La réponse la plus simple qui soit:

Supprimer un point de méthodes sans paramètres est DÉCONSEILLÉ !

List(1,2,3) reverse //is bad style and will lead to unpredicted behaviour
List(1,2,3) map(_*2) reverse //bad too, because reverse can take first method call from the next line (details below)

OK pour déposer un point dans les méthodes qui prennent un paramètre de fonction d'ordre supérieur comme la carte, filtrer, compter et être en sécurité! Aussi, purement fonctionnel des méthodes comme Zip.

List(1,2,3) map(_*2) filter(_>2)
(List(1,2,3) map(_*2)).reverse //safe and good
List(1,3,5) Zip List(2,4,6)

Réponse longue POURQUOI

case class MyBool(x: Boolean) {
  def !!! = MyBool(!x) //postfix
  def or(other: MyBool): MyBool = if(x) other else this //infix
  def justMethod0() = this //method with empty parameters
  def justMethod2(a: MyBool, b: MyBool) = this //method with two or more
  override def toString = if(x) "true" else "false"
}

1) Opérateur Postfix - est en fait un appel de méthode sans paramètres (a! == a.!) Et sans crochets. (considéré comme non sûr et obsolète)

val b1 = MyBool(false) !!!
List(1,2,3) head

2) L'opérateur Postfix est une méthode qui devrait terminer la ligne, sinon elle sera traitée comme infixe.

val b1 = MyBool(true) no! no! //ERROR
//is actually parsed like
val b2 = MyBool(true).no!(no!) //(no!) is unknown identifier
//as bad as
Vector(1,2,3) toList map(_*2) //ERROR

3) L'opérateur Infix est une méthode avec un paramètre, qui peut être appelée sans point ni parenthèses. Uniquement pour les méthodes purement fonctionnelles

val c1 = MyBool(true) or b1 or MyBool(true)
val c2 = MyBool(true).or(b1).or(MyBool(true))
c1 == c2

4) La méthode avec un ou plusieurs paramètres enchaînera sans point si vous l'appelez avec des paramètres. def a (), def a (x), def a (x, y) Mais vous ne devriez le faire que pour les méthodes qui utilisent fonction d'ordre supérieur comme paramètre!

val d1 = MyBool(true) justMethod2(b1, c1) or b1 justMethod0() justMethod2(c1, b1)
//yes, it works, but it may be confusing idea
val d2 = MyBool(true).justMethod2(b1,c1).or(b1).justMethod0().justMethod2(c1, b1)
d1 == d2
//looks familiar? This is where it should be used:
List(1,2,3) filter(_>1) map(_*2)

Exemples d'avertissements:

avertissement: il y a eu 1 avertissement (s) de dépréciation; réexécutez avec -deprecation pour plus de détails avertissement: l'opérateur postfix tail doit être activé en rendant visible la valeur implicite scala.language.postfixOps. Ceci peut être réalisé en ajoutant la clause d'importation 'import scala.language.postfixOps' ou en définissant l'option du compilateur -language: postfixOps. Voir les documents Scala pour la valeur scala.language.postfixOps pour une discussion sur la raison pour laquelle la fonctionnalité doit être explicitement activée.

30
Alex

Il fait référence à la possibilité d'appeler une méthode nullary (sans liste d'arguments ou liste d'arguments vide) en tant qu'opérateur postfix:

Par exemple:

case class MyBool(value: Boolean) {
    def negated = new MyBool(!value)
}
val b1 = MyBool( true )
val b2 = b1 negated // Same as b1.negated

Voir: http://www.scala-lang.org/node/118

5
Régis Jean-Gilles