2011-12-18 10 views
5
def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => test(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

Perché devo specificare esplicitamente il tipo di _ quando sembra inferirabile dal contesto?informazioni di tipo ridondanti sui parametri nella definizione di funzione parzialmente applicata

MODIFICA: Ridenominato per evitare la collisione del nome in seguito al suggerimento di David Soergel.

risposta

3

Prima di tutto, per evitare confusione tra "test def" e "test val", scriviamo:

def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => foo(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

Cosa c'è corollari degli contesto è solo che l'argomento a barra deve in qualche modo essere convertibile in una stringa . Ciò potrebbe essere dovuto all'ereditarietà (se al posto di String si utilizza un tipo non finale lì) o a causa di una conversione implicita.

Fondamentalmente il potenziale implicito significa che l'argomento su bar potrebbe essere praticamente di qualsiasi tipo, quindi il codice così come scritto è effettivamente sottodimensionato. Non so se il compilatore verifica effettivamente se ci sono conversioni implicite appropriate nell'oscilloscopio prima di emettere l'errore di tipo "mancante", ma non lo direi. (Nel caso di String ci sarà probabilmente un regalo di gruppo, comunque). Sarebbe fragile e confuso se la firma di baz fosse cambiata in seguito all'importazione di un nuovo implicito che poteva produrre una stringa.

+1

Grazie per la correzione del nome. Ma 'def foo (num: Int) = 1; val bar = pippo (_) 'compila bene. Quindi non penso che l'ereditarietà o le conversioni implicite causino l'errore. – xiefei

+0

Huh-- scusa, per ulteriori riflessioni la mia argomentazione sugli impliciti non ha comunque senso. Il compilatore potrebbe infatti solo dedurre il tipo dell'argomento della barra da String e quindi consentire impliciti quando si chiama la barra, come al solito. –

3

Penso spiegazione di David Soergel è sostanzialmente corretta: se il tipo T ha una conversione implicita a stringa poi val bar = foo(3, _:T) è valida, dando in funzione del tipo di T => Int, che non è correlato al String => Int.

Perché il compilatore non fa un'ipotesi ragionevole (in assenza di digitazione esplicita) che il tipo è in realtà lo stesso che nel metodo (che è l'essenza della tua domanda), non lo so - Posso solo supporre che sia perché complicherebbe le specifiche linguistiche.

Dove non sono specificati tipi, cioè val bar = foo(_, _), sembra il compilatore interpreta come semplice eta-conversione, la stessa val bar = foo _, che fa invia un String => Int.

mio idioma preferito sarebbe quello di dare il tipo di funzione sul lato sinistro, che ha il vantaggio di permettere di vedere facilmente il tipo s' bar:

val bar: String => Int = foo(3, _) 

Se siete allergici di ri- digitando la parola String, è possibile scrivere

val bar = (foo _).curried(3) 
+0

"Sintassi segnaposto per funzioni anonime" parte di scala spec (2.8) non fornisce informazioni su come viene inferito il tipo "_". La mancanza di specifiche potrebbe essere la causa di questa incoerenza del compilatore. – xiefei

Problemi correlati