2012-10-11 12 views
5

Perché non è possibile avere i parametri di tipo nei metodi di fabbrica riportati di seguito?Scala Array mappa restituisce ArraySeq

import org.junit.runner.RunWith 
import org.scalatest.junit.JUnitRunner 
import org.scalatest.FunSuite 

@RunWith(classOf[JUnitRunner]) 
class WhyScalaNeverWillMakeIt extends FunSuite { 

    test("Array becomes ArraySeq when you least want it") { 
    val arr = Array("A", "B", "C") 
    def f: String => Dummy = new Dummy(_) 

    val bucket = new Bucket[Dummy](arr.map(f)) 
// val bucket2 = Bucket[String, Dummy](arr, f) 
// val bucket3 = Bucket[Dummy](arr, f) 
    val bucket4 = Bucket(arr, f) 
    } 

    class Bucket[T](val arr: Array[T]) {/* Loads of business logic */} 

    object Bucket { 
// def apply[T, U](arr: Array[T], f:T=>U):Bucket[U] = new Bucket[U](arr.map(b => f(b))) 
// def apply[T](arr: Array[String], f:String=>T):Bucket[T] = new Bucket[T](arr.map(b => f(b))) 
    def apply(arr: Array[String], f:String=>Dummy):Bucket[Dummy] = new Bucket[Dummy](arr.map(f)) 
    } 


    class Dummy(val name: String) 
} 

Se Decommentare i metodi di fabbrica in object Bucket ottengo:

error: type mismatch; 
found : scala.collection.mutable.ArraySeq[T] 
required: Array[T] 
def apply[T](arr: Array[String], f:String=>T):Bucket[T] = new Bucket[T](arr.map(b => f(b))) 

In qualche modo il compilatore Scala po 'confusa (o sono io ;-)?), Quando ho introdotto il parametro di tipo T. Forse Sto facendo qualcosa di molto sbagliato qui, ma non riesco a capire perché l'introduzione di un parametro di tipo significhi che la funzione mappa debba cambiare il tipo di ritorno da Array [T] a ArraySeq [T].

So che Array è solo un wrapper attorno a Java Array e che probabilmente dovrei usare una delle classi di Scala più fantasiose, come Seq o List, ma che comunque non spiega questo comportamento piuttosto strano.

Qualcuno può spiegare perché questo sta accadendo e forse anche come risolverlo (usando ancora gli Array)?

Edit: sto usando Scala 2.9.1

risposta

5

Basta aggiungere ClassManifest contesto legato:

def apply[T, U: ClassManifest](arr: Array[T], f: T => U): Bucket[U] = new Bucket[U](arr.map(b => f(b))) 
    def apply[T: ClassManifest](arr: Array[String], f: String => T): Bucket[T] = new Bucket[T](arr.map(b => f(b))) 

Per i dettagli controllare this e this

+0

OK, grazie Sergey, che ha fatto il trucco. Ora devo solo leggere e capire i collegamenti che hai fornito. Forse c'è qualcosa che mi farà accettare la brutta sintassi ++ con [T: ClassManifest]. – Jorgen

+1

So cosa può farti accettare quella sintassi, vedere a cosa serve desugars: def foo [T: Bar] diventa def foo [T] (implicito generateName: Bar [T]) –