2010-06-27 8 views
11

Il compilatore Scala può spesso dedurre i tipi di restituzione per i metodi, ma ci sono alcune circostanze in cui è necessario specificare il tipo di ritorno. I metodi ricorsivi, ad esempio, richiedono che venga specificato un tipo di ritorno.Quando è richiesto un tipo di ritorno per i metodi in Scala?

Mi accorgo che a volte viene visualizzato il messaggio di errore "metodo sovraccaricato (metodo) richiede tipo restituito", ma non è una regola generale che i tipi restituiti devono sempre essere specificati per i metodi sovraccaricati (Ho esempi in cui non ottengo questo errore).

Quando è necessario specificare esattamente un tipo di ritorno, per i metodi in generale e in particolare per i metodi sovraccaricati?

+4

Come una questione di (il mio stile personale), io do tipi restituiti espliciti per tutti, ma i metodi più semplici (sostanzialmente, uno-liners senza logica condizionale). Tenere presente che se si consente al compilatore di dedurre il tipo di risultato di un metodo, potrebbe essere più specifico di quanto si desideri. (Ad es., 'HashMap' invece di' Map'.) –

+0

@Randall yes, buon punto (sul tipo di ritorno che è troppo specifico). – Jesper

risposta

18

La Chapter 2. Type Less, Do More del libro Programming Scala menzioni:

Quando annotazioni di tipo esplicite sono obbligatori.

In termini pratici, è necessario fornire le annotazioni di tipo esplicite per le seguenti situazioni:

valori di ritorno Metodo nei seguenti casi:

  • Quando si chiama esplicitamente il ritorno in un metodo (anche a fine).
  • Quando un metodo è ricorsivo.
  • Quando un metodo è sovraccarico e uno dei metodi ne chiama un altro. Il metodo di chiamata ha bisogno di un'annotazione del tipo di ritorno.
  • Quando il tipo di reso indicato è più generico di quanto previsto, ad es. Any.

Esempio:

// code-examples/TypeLessDoMore/method-nested-return-script.scala 
// ERROR: Won't compile until you put a String return type on upCase. 

def upCase(s: String) = { 
    if (s.length == 0) 
    return s // ERROR - forces return type of upCase to be declared. 
    else 
    s.toUpperCase() 
} 

metodi di overload a volte può richiedere un tipo di ritorno esplicito. Quando uno di questi metodi ne chiama un altro, dobbiamo aggiungere un tipo di ritorno a quello che sta facendo la chiamata, come in questo esempio.

// code-examples/TypeLessDoMore/method-overloaded-return-script.scala 
// Version 1 of "StringUtil" (with a compilation error). 
// ERROR: Won't compile: needs a String return type on the second "joiner". 

object StringUtil { 
    def joiner(strings: List[String], separator: String): String = 
    strings.mkString(separator) 

    def joiner(strings: List[String]) = joiner(strings, " ") // ERROR 
} 
import StringUtil._ // Import the joiner methods. 

println(joiner(List("Programming", "Scala"))) 

I due metodi joiner concatenare una List di stringhe insieme.
Il primo metodo accetta anche un argomento per la stringa di separazione.
Il secondo metodo chiama il primo con un separatore "predefinito" di un singolo spazio.

Se si esegue questo script, si verifica il seguente errore.

... 9: error: overloaded method joiner needs result type 
def joiner(strings: List[String]) = joiner(strings, "") 

Poiché il secondo metodo joiner chiama il primo, esso richiede un tipo String ritorno esplicito.Esso dovrebbe essere simile a questo:

def joiner(strings: List[String]): String = joiner(strings, " ") 

In sostanza, specificando il tipo di ritorno può essere una buona pratica anche se Scala può dedurre che.


Randall Schulz commenti:

Come una questione di (mio personale) di stile, io do tipi restituiti espliciti per tutti, ma i metodi più semplici (sostanzialmente, uno-liners senza logica condizionale).

Tenere presente che se si consente al compilatore di dedurre il tipo di risultato di un metodo, potrebbe essere più specifico di quanto si desideri. (Per esempio, invece di HashMap Map.)

E dal momento che si può decidere di esporre l'interfaccia minimale nel vostro tipo di ritorno (si veda ad esempio questo SO question), questo tipo di inferenza potrebbe ottenere nel modo.


E circa l'ultimo scenario ("Quando il tipo di ritorno inferito sarebbe più generale di quanto previsto"), Ken Bloom aggiunge:

specificare il tipo restituito quando si desidera che il compilatore di verificare che il codice nella funzione restituisce il tipo che si aspettava

(il codice difettoso che innesca una "più generale di tipo rendimento atteso era:

// code-examples/TypeLessDoMore/method-broad-inference-return-script.scala 
// ERROR: Won't compile. Method actually returns List[Any], which is too "broad". 

def makeList(strings: String*) = { 
    if (strings.length == 0) 
    List(0) // #1 
    else 
    strings.toList 
} 

val list: List[String] = makeList() // ERROR 

, che erroneamente interpretato ed List [Qualunque] perché restituendo un elenco vuoto, ma Ken chiamato fuori:

List(0) non crea una lista con 0 elementi.
Crea un List[Int] contenente un elemento (il valore 0).
Quindi un List[Int] su un ramo condizionale e uno List[String] sull'altro ramo condizionale generalizza a List[Any].
In questo caso, il typer non è eccessivamente generico: si tratta di un bug nel codice.
)

+0

"Quando il tipo di reso inferito è più generico di quanto previsto, ad es. Qualsiasi." Questo è strano In realtà, considererei un bug nel Typer. Non ho mai provato qualcosa del genere. Hai un esempio? – soc

+0

@soc: http://programming-scala.labs.oreilly.com/ch02.html ha un esempio in cui restituire un 'List (0)' ('List' di dimensione 0) restituirà e' List [Any] 'invece di' List [String] 'a meno che non si specifichi il tipo restituito. – VonC

+2

'Lista (0)' non crea una lista con 0 elementi. Crea un 'List [Int]' contenente un elemento (il valore '0'). Quindi un 'List [Int]' su un ramo condizionale e un 'List [String]' sull'altro ramo condizionale generalizza a 'List [Any]'. In questo caso, il typer non è eccessivamente generico: è un bug nel codice. Che aggiunge un'altra regola per specificare i tipi di ritorno: ** specifica il tipo di ritorno quando vuoi che il compilatore verifichi che il codice nella funzione restituisca il tipo che ti aspettavi. ** –

Problemi correlati