2011-12-20 13 views
24

Si prega di inserire questo.Tipi di Scala, Lungo, Int, ecc

scala> 86400000 * 150 
res0: Int = 75098112 


scala> val i : Long = 86400000 * 150 
i: Long = 75098112 


val i = 86400000 * 150.asInstanceOf[Long] 
i: Long = 12960000000 

val i = 86400000 * 150L 
i: Long = 12960000000 

Che cosa nel mondo sta succedendo qui? Sono stato paracadutismo e devo dire che questa è la cosa più pericolosa che abbia mai visto. Nessun controllo del compilatore per questo? Ovviamente se stavo sostituendo 150 per una variabile che è diversa.

* EDIT *

Questo è stato il codice vero e proprio che mi preoccupa.

val oneDay = 86400000 
val days150 = oneDay * 150 

days150 = 75098112 

Questa non era colpa di Scala o di nessuno tranne la mia. Mi ha solo fatto preoccupare.

+13

Si prega di non votare questa domanda verso il basso. È una domanda legittima e l'overflow dei numeri interi è molto pericoloso e causa reali problemi con i programmi reali. Il fatto che sia comune a molte lingue e non solo a Scala, non lo rende ingiustificato. –

+1

Quando hai bisogno di numeri davvero grandi, c'è sempre [BigInteger] (http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigInteger.html). È un po 'goffo, ma funziona. –

+1

Votato per chiudere; questo è più di una lamentela che di una domanda. I vari esempi illustrano che l'interrogante sa già esattamente cosa sta succedendo: overflow intero. –

risposta

15

Non c'è nulla di specifico su Scala. È solo questione del tipo di destinazione del compito irrilevante per il tipo in cui viene eseguita un'operazione (moltiplicazione in questo caso).

Ad esempio, in C#:

using System; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     int a = unchecked(86400000 * 150); 
     long b = unchecked(86400000 * 150); 
     long c = 86400000 * (long) 150; 
     long d = 86400000 * 150L; 
     Console.WriteLine(a); // 75098112 
     Console.WriteLine(b); // 75098112 
     Console.WriteLine(c); // 12960000000 
     Console.WriteLine(d); // 12960000000 
    } 
} 

La unchecked parte qui è perché il compilatore C# è abbastanza intelligente per capire che i trabocchi di funzionamento, ma solo perché entrambi gli operandi sono costanti. Se uno degli operandi fosse una variabile, sarebbe andato bene senza unchecked.

Allo stesso modo in Java:

public class Program 
{ 
    public static void main(String[] args) 
    { 
     int a = 86400000 * 150; 
     long b = 86400000 * 150; 
     long c = 86400000 * (long) 150; 
     long d = 86400000 * 150L; 
     System.out.println(a); // 75098112 
     System.out.println(b); // 75098112 
     System.out.println(c); // 12960000000 
     System.out.println(d); // 12960000000 
    } 
} 
+0

Grazie per questo. Non ho mai notato questo problema con Java per qualche ragione. –

+3

Blame C. Sia Scala che C# hanno copiato le loro regole in formato fisso da Java e Java in pratica hanno copiato le sue regole da C++ che a loro volta le ha clonate da C. –

+4

Che a sua volta le ha prese da FORTRAN, che le ha prese da ASM. Triste.Siamo in una professione che non esisteva quando nacque mio padre e siamo come studiosi talmudici che studiano testi antichi. – Malvolio

0

E 'ovvio non c'è fusione implicita in corso. 86400000 * 150 è visto come int * int da immagino il jvm. Viene calcolato quindi assegnato a qualsiasi tipo di variabile che desideri che non fa differenza. Quindi, la cosa corretta da fare è assicurarsi che almeno uno dei numeri o delle variabili vengano trasmessi come un tipo lungo, 86400000 * 150.toLong. Jvm appare come predefinito per il tipo più grande.

Btw, credo che un controllo di overflow sull'estremità dello scala avrebbe solo paralizzato le prestazioni. Pertanto, l'omissione della conversione automatica dei tipi introduce rischi ma consente prestazioni migliori. Devi solo stare attento ..., che dovrebbe essere una seconda natura se provi da un backup c/C++.

Problemi correlati