2017-05-06 1 views
1

J'ai commencé à jouer avec Scala il y a quelques jours. Ce que je voulais faire est d'écrire une très petite classe qui représenterait des nombres naturels et j'aimerais qu'elle soit implicitement convertible de/vers Int. Honnêtement, je n'ai pas beaucoup fait jusqu'à présent. Voici le code:Collé créant implicitement convertible de/vers les numéros Natgural Int

object main { 
    class Natural(n: Int) { 
    def isDividerOf(m: Natural): Boolean = m % n == 0 
    } 

    implicit def Int(m: Natural): Int = m 
    implicit def Natural(n: Int): Natural = new Natural(n) 

    def main(args: Array[String]) ={ 
    println("test") 
    println(60 isDividerOf 600) 
    } 
} 

Le code est en mesure de compiler, mais quand je le lance (peu importe les chiffres que j'utilise comme arguments à isDividerOf) l'exécution du programme est toujours en pause/suspendu, autrement dit après l'impression test il ne sort rien, non il sort correctement.

Qu'est-ce que je fais mal?

Répondre

3

Votre définition pour le implicit Natural => Int est responsable de la récursion infinie; ce que vous avez écrit est équivalent à ce qui suit (explicitant les conversions implicites dans votre code):

implicit def Int2Nat(m: Natural): Int = Int2Nat(m) 

Qu'est-ce que vous voulez à la place:

implicit def Int2Nat(m: Natural): Int = m.n // Also change n to a val 

J'ai obtenu cette information en compilant votre code avec scalac -Xprint:typer, qui montre la représentation interne du compilateur de votre code après qu'il a été TypeChecked (et tous implicits ont été résolus):

$ scalac -Xprint:typer so.scala 
[[syntax trees at end of      typer]] // s.scala 
package <empty> { 
    object main extends scala.AnyRef { 
    def <init>(): main.type = { 
     main.super.<init>(); 
    () 
    }; 
    class Natural extends scala.AnyRef { 
     <paramaccessor> private[this] val n: Int = _; 
     <stable> <accessor> <paramaccessor> def n: Int = Natural.this.n; 
     def <init>(n: Int): main.Natural = { 
     Natural.super.<init>(); 
     () 
     }; 
     def isDividerOf(m: main.Natural): Boolean = main.this.Int(m).%(Natural.this.n).==(0) 
    }; 
    implicit def Int(m: main.Natural): Int = main.this.Int(m); 
    implicit def Natural(n: Int): main.Natural = new main.this.Natural(n); 
    def main(args: Array[String]): Unit = { 
     scala.Predef.println("test"); 
     scala.Predef.println(main.this.Natural(60).isDividerOf(main.this.Natural(600))) 
    } 
    } 
} 

Mais veuillez ne pas utiliser de conversions implicites. Déjà. Ils sont le diable.
Vous pouvez obtenir le même résultat avec une méthode d'extension sur Int:

implicit class isDividerOfOp(i: Int) { 
    def isDividerOf(other: Int): Boolean = other % i == 0 
} 
+0

Merci @OlivierBlanvillain. Le bit '' -Xprint: typer''' était vraiment utile, mon mauvais je ne le savais pas. Pouvez-vous expliquer pourquoi vous ne suggérez pas d'utiliser des conversions implicites? Parce qu'ils sont la source de confusions ou qu'il y a une autre raison? J'ai honnêtement eu l'impression qu'il est très commun à Scala. – Gonzalez

+1

Le fait que vous, en tant que débutant, soit confus par des conversions implicites au point où vous avez pris le temps d'aller sur SO et de poser cette question est un bon indicateur que les conversions implicites sont une grande source de confusion. Il y a beaucoup à dire sur le sujet, s'il vous plaît ouvrir une autre question "Pourquoi je ne devrais pas utiliser les conversions implicites dans mon code?" :) – OlivierBlanvillain