2013-06-24 11 views
5

Stavo guardando la definizione di toArray per HashMaps:Perché lo scaladoc dice che HashMap.toArray restituisce l'array [A] invece di Array [(A, B)]?

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.HashMap

Ha

toArray: Array[A] 
def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B] 

io non capisco questo - il primo bit dice che si ottiene un array [A] , ma la seconda parte dice che ottieni Array [B]? Nessuno di questi sono quello che mi aspetto - Array [(A, B)]

Quando controllo io stesso:

scala> val x = scala.collection.mutable.HashMap[String, Int]() 
x: scala.collection.mutable.HashMap[String,Int] = Map() 

scala> x.put("8", 7) 
res0: Option[Int] = None 

scala> x foreach println 
(8,7) 

scala> x.toArray 
res2: Array[(String, Int)] = Array((8,7)) 

perché non è come toList?

toList: scala.List[(A, B)] 
+0

Tutte le risposte eccellenti, grazie! – Austin

risposta

5

Lo scaladoc ha tutti i tipi di bug sottili. Il problema qui è che stai vedendo la versione "semplificata" della firma del metodo (intesa come un modo per trasmettere la parte essenziale della firma e nascondere elementi come CanBuildFrom nei metodi map/flatMap, che sono davvero un dettaglio di implementazione). La semplificazione è andata un po 'storta qui, e non sembra avere molto senso. Se si fa clic sul "firma pieno" di collegamento, vedrai che la firma vera e propria si presenta come:

def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B] 

In realtà questo è ancora sbagliata, in quanto non possiamo certo avere un tipo B dove B>: (A, B). Dovrebbe essere più simile:

def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C] 

Il problema è che ci sono due B s: il primo deriva dalla dichiarazione HashMap classe stessa (HashMap[A, +B]) mentre l'altro viene dai metodi toArray definiti nella sua base classe TraversableOnce (def toArray[B >: A](implicit arg0: ClassTag[B]): Array[B]). Succede solo che il generatore di scaladoc non è riuscito a deduplicare le due istanze di B

2

L'API che vedete nella la scaladoc di toArray:

def toArray[B >: (A, B)](implicit arg0: ClassTag[B]): Array[B] 

è equivalente a:

def toArray[C >: (A, B)](implicit arg0: ClassTag[C]): Array[C] 

La scelta del tipo di variabile B è davvero sfortunato (e forse anche un bug Scaladoc, non sono sicuro che tu sia autorizzato a scriverlo).

Significa fondamentalmente si otterrà una serie di supertipo più specifico di (A,B)per i quali è disponibile ClassTag. È necessario il ClassTag per creare lo Array.

Ciò significa in sostanza che se in fase di compilazione, il tipo di tempo di esecuzione dello Map che si sta convertendo è completamente noto, si otterrà un Array[(A,B)]. Tuttavia, se è stato effettuato il lancio in up-cast del proprio Map da qualche parte, il tipo di esecuzione del risultante Array dipenderà dal tipo up-casted e non dal tipo runtime. Questo è diverso comportamento di toList e a causa delle restrizioni JVM su come possono essere creati gli array nativi.

1

Lo scaladoc è solo sbagliato, perché eredita toArray da TraversableOnce, dove il tipo della collezione è A e il valore di ritorno è B. La cosa Array[A] viene lasciata da TraversableOnce dove A è qualsiasi cosa che sia TraversableOnce attraversante (in questo caso, in realtà (A,B) per una diversa definizione di A e B); e sebbene riempia correttamente il (A,B) nel formato lungo, utilizza ancora B come nuova variabile di ritorno invece di una lettera diversa come C.

Tipo di confusione! E 'in realtà dovrebbe leggere

def toArray[C >: (A,B)](...[C]): Array[C] 

e breve modulo dovrebbe essere

toArray: Array[(A,B)] 

proprio come ci si aspetta.

Problemi correlati