2010-06-27 10 views
11

Der Scala-Compiler kann oft Rückgabetypen für Methoden ableiten, aber unter Umständen muss der Rückgabetyp angegeben werden. Bei rekursiven Methoden muss beispielsweise ein Rückgabetyp angegeben werden.Wann ist ein Rückgabetyp für Methoden in Scala erforderlich?

Ich bemerke, dass manchmal die Fehlermeldung "Überladene Methode (Methodenname) erfordert Rückgabetyp", aber es ist keine allgemeine Regel, dass Rückgabetypen immer für überladene Methoden angegeben werden müssen (Ich habe Beispiele, wo ich nicht bekomme dieser Fehler).

Wann genau muss ein Rückgabetyp angegeben werden, für Methoden im Allgemeinen und speziell für überladene Methoden?

+4

Als eine Frage der (mein persönlicher) Stil, gebe ich expliziten Rückgabetypen für alle, aber die meisten einfachen Methoden (im Grunde, Einzeiler ohne bedingte Logik). Denken Sie daran, dass der Compiler dann, wenn Sie den Ergebnistyp einer Methode ableiten, möglicherweise genauer ist als Sie möchten. (Z. B. 'HashMap' anstelle von' Map'). –

+0

@Randall ja, guter Punkt (der Rückgabetyp ist zu spezifisch). – Jesper

Antwort

18

Die Chapter 2. Type Less, Do More des Programming Scala Buch erwähnt:

Wenn Explicit Geben Sie Anmerkungen erforderlich sind.

In der Praxis haben Sie explizite Typenannotationen für die folgenden Situationen bieten:

Methode Rückgabewerte in den folgenden Fällen:

  • Wenn Sie explizit Rückkehr in einer Methode aufrufen (auch bei das Ende).
  • Wenn eine Methode rekursiv ist.
  • Wenn eine Methode überladen ist und eine der Methoden eine andere aufruft. Die aufrufende Methode benötigt eine Annotation des Rückgabetyps.
  • Wenn der abgeleitete Rückgabetyp allgemeiner ist, als Sie beabsichtigten, z. B. Any.

Beispiel:

// 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() 
} 

Überladene Methoden kann manchmal einen expliziten Rückgabetyp erfordern. Wenn eine solche Methode eine andere aufruft, müssen wir einen Rückgabetyp zu demjenigen hinzufügen, der den Aufruf ausführt, wie in diesem Beispiel.

// 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"))) 

Die beiden Methoden joiner verketten zusammen eine List von Strings.
Die erste Methode nimmt auch ein Argument für die Trennzeichenfolge.
Die zweite Methode ruft die erste mit einem "default" Trennzeichen eines einzelnen Platzes auf.

Wenn Sie dieses Skript ausführen, erhalten Sie den folgenden Fehler.

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

Da das zweite Verfahren joiner die ersten Aufforderungen, es erfordert einen expliziten String Rückgabetyp.Es sollte wie folgt aussehen:

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

Grundsätzlich den Rückgabetyp Angabe kann auch eine gute Übung sein, obwohl Scala es ableiten kann.


Randall Schulz Kommentare:

Als eine Frage der (mein persönlicher) Stil, gebe ich expliziten Rückgabetypen für alle, aber die meisten einfachen Methoden (im Grunde, Einzeiler ohne bedingte Logik).

Denken Sie daran, wenn Sie den Compiler auf den Ergebnistyp einer Methode schließen lassen, ist dies möglicherweise genauer als gewünscht. (Zum Beispiel HashMap anstelle von Karte.)

Und da Sie die minimale Schnittstelle in Ihrem Rückgabetyp aussetzen möchten (siehe zum Beispiel das SO question), diese Art von Folgerung könnte in die Quere kommen.


Und über das letzte Szenario („Wenn der gefolgert Rückgabetyp allgemeiner sein würde, als Sie gedacht“), Ken Bloom fügt hinzu:

den Rückgabetyp angeben, wenn Sie die Compiler überprüfen mögen dass Code in der Funktion gibt den Typen Sie erwartet

(den fehlerhaften Code, der ein „allgemeine als erwarteten Rückgabetyp auslöst war:

// 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 

, die ich falsch interpretiert und List [Alles], weil eine leere Liste zurückkehrt, aber Ken rief es aus:

List(0) erstellen keine Liste mit 0 Elementen.
Erzeugt ein List[Int] mit einem Element (der Wert 0).
Also eine List[Int] auf einer bedingten Verzweigung und eine List[String] auf der anderen bedingten Verzweigung verallgemeinern zu List[Any].
In diesem Fall der Typer ist nicht allzu allgemein - es ist ein Fehler im Code.
)

+0

"Wenn der abgeleitete Rückgabetyp allgemeiner ist als von Ihnen beabsichtigt, z. B. Beliebig." Das ist seltsam. Eigentlich würde ich das als einen Fehler im Typer betrachten. So etwas habe ich noch nie erlebt. Hast du ein Beispiel? – soc

+0

@soc: http://programming-scala.labs.oreilly.com/ch02.html hat ein Beispiel, in dem eine 'List (0)' ('List' von Größe 0) zurückgibt und' List [Any] 'anstelle von' List [String] 'zurückgibt, außer Sie geben den Rückgabetyp an. – VonC

+2

'List (0)' erstellt keine Liste mit 0 Elementen. Es erzeugt eine "Liste [Int]", die ein Element enthält (den Wert "0"). So verallgemeinern 'List [Int]' auf einer bedingten Verzweigung und 'List [String]' auf der anderen bedingten Verzweigung zu 'List [Any]'. In diesem Fall ist der Tipp nicht zu allgemein - es ist ein Fehler im Code. Dadurch wird eine weitere Regel zur Angabe von Rückgabetypen hinzugefügt: ** Geben Sie den Rückgabetyp an, wenn der Compiler überprüfen soll, ob der Code in der Funktion den erwarteten Typ zurückgibt. ** –

Verwandte Themen